wine-wine/graphics/x11drv/dib.c

4071 lines
132 KiB
C

/*
* X11DRV device-independent bitmaps
*
* Copyright 1993,1994 Alexandre Julliard
*/
#include "config.h"
#include "ts_xlib.h"
#include "ts_xutil.h"
#ifdef HAVE_LIBXXSHM
# include "ts_xshm.h"
# ifdef HAVE_SYS_SHM_H
# include <sys/shm.h>
# endif
# ifdef HAVE_SYS_IPC_H
# include <sys/ipc.h>
# endif
#endif /* defined(HAVE_LIBXXSHM) */
#include <stdlib.h>
#include <string.h>
#include "windef.h"
#include "bitmap.h"
#include "x11drv.h"
#include "debugtools.h"
#include "gdi.h"
#include "palette.h"
#include "global.h"
DEFAULT_DEBUG_CHANNEL(bitmap);
DECLARE_DEBUG_CHANNEL(x11drv);
static int ximageDepthTable[32];
#ifdef HAVE_LIBXXSHM
static int XShmErrorFlag = 0;
#endif
/* This structure holds the arguments for DIB_SetImageBits() */
typedef struct
{
struct tagDC *dc;
LPCVOID bits;
XImage *image;
PALETTEENTRY *palentry;
int lines;
DWORD infoWidth;
WORD depth;
WORD infoBpp;
WORD compression;
RGBQUAD *colorMap;
int nColorMap;
Drawable drawable;
GC gc;
int xSrc;
int ySrc;
int xDest;
int yDest;
int width;
int height;
DWORD rMask;
DWORD gMask;
DWORD bMask;
BOOL useShm;
int dibpitch;
} X11DRV_DIB_IMAGEBITS_DESCR;
enum Rle_EscapeCodes
{
RLE_EOL = 0, /* End of line */
RLE_END = 1, /* End of bitmap */
RLE_DELTA = 2 /* Delta */
};
/***********************************************************************
* X11DRV_DIB_GetXImageWidthBytes
*
* Return the width of an X image in bytes
*/
inline static int X11DRV_DIB_GetXImageWidthBytes( int width, int depth )
{
if (!depth || depth > 32) goto error;
if (!ximageDepthTable[depth-1])
{
XImage *testimage = XCreateImage( gdi_display, visual, depth,
ZPixmap, 0, NULL, 1, 1, 32, 20 );
if (testimage)
{
ximageDepthTable[depth-1] = testimage->bits_per_pixel;
XDestroyImage( testimage );
}
else ximageDepthTable[depth-1] = -1;
}
if (ximageDepthTable[depth-1] != -1)
return (4 * ((width * ximageDepthTable[depth-1] + 31) / 32));
error:
WARN( "(%d): Unsupported depth\n", depth );
return 4 * width;
}
/***********************************************************************
* X11DRV_DIB_CreateXImage
*
* Create an X image.
*/
XImage *X11DRV_DIB_CreateXImage( int width, int height, int depth )
{
int width_bytes;
XImage *image;
wine_tsx11_lock();
width_bytes = X11DRV_DIB_GetXImageWidthBytes( width, depth );
image = XCreateImage( gdi_display, visual, depth, ZPixmap, 0,
calloc( height, width_bytes ),
width, height, 32, width_bytes );
wine_tsx11_unlock();
return image;
}
/***********************************************************************
* X11DRV_DIB_GenColorMap
*
* Fills the color map of a bitmap palette. Should not be called
* for a >8-bit deep bitmap.
*/
int *X11DRV_DIB_GenColorMap( DC *dc, int *colorMapping,
WORD coloruse, WORD depth, BOOL quads,
const void *colorPtr, int start, int end )
{
int i;
if (coloruse == DIB_RGB_COLORS)
{
if (quads)
{
RGBQUAD * rgb = (RGBQUAD *)colorPtr;
if (depth == 1) /* Monochrome */
for (i = start; i < end; i++, rgb++)
colorMapping[i] = (rgb->rgbRed + rgb->rgbGreen +
rgb->rgbBlue > 255*3/2);
else
for (i = start; i < end; i++, rgb++)
colorMapping[i] = X11DRV_PALETTE_ToPhysical( dc, RGB(rgb->rgbRed,
rgb->rgbGreen,
rgb->rgbBlue));
}
else
{
RGBTRIPLE * rgb = (RGBTRIPLE *)colorPtr;
if (depth == 1) /* Monochrome */
for (i = start; i < end; i++, rgb++)
colorMapping[i] = (rgb->rgbtRed + rgb->rgbtGreen +
rgb->rgbtBlue > 255*3/2);
else
for (i = start; i < end; i++, rgb++)
colorMapping[i] = X11DRV_PALETTE_ToPhysical( dc, RGB(rgb->rgbtRed,
rgb->rgbtGreen,
rgb->rgbtBlue));
}
}
else /* DIB_PAL_COLORS */
{
if (colorPtr) {
WORD * index = (WORD *)colorPtr;
for (i = start; i < end; i++, index++)
colorMapping[i] = X11DRV_PALETTE_ToPhysical( dc, PALETTEINDEX(*index) );
} else {
for (i = start; i < end; i++)
colorMapping[i] = X11DRV_PALETTE_ToPhysical( dc, PALETTEINDEX(i) );
}
}
return colorMapping;
}
/***********************************************************************
* X11DRV_DIB_BuildColorMap
*
* Build the color map from the bitmap palette. Should not be called
* for a >8-bit deep bitmap.
*/
int *X11DRV_DIB_BuildColorMap( DC *dc, WORD coloruse, WORD depth,
const BITMAPINFO *info, int *nColors )
{
int colors;
BOOL isInfo;
const void *colorPtr;
int *colorMapping;
if ((isInfo = (info->bmiHeader.biSize == sizeof(BITMAPINFOHEADER))))
{
colors = info->bmiHeader.biClrUsed;
if (!colors) colors = 1 << info->bmiHeader.biBitCount;
colorPtr = info->bmiColors;
}
else /* assume BITMAPCOREINFO */
{
colors = 1 << ((BITMAPCOREHEADER *)&info->bmiHeader)->bcBitCount;
colorPtr = (WORD *)((BITMAPCOREINFO *)info)->bmciColors;
}
if (colors > 256)
{
ERR("called with >256 colors!\n");
return NULL;
}
/* just so CopyDIBSection doesn't have to create an identity palette */
if (coloruse == (WORD)-1) colorPtr = NULL;
if (!(colorMapping = (int *)HeapAlloc(GetProcessHeap(), 0,
colors * sizeof(int) )))
return NULL;
*nColors = colors;
return X11DRV_DIB_GenColorMap( dc, colorMapping, coloruse, depth,
isInfo, colorPtr, 0, colors);
}
/***********************************************************************
* X11DRV_DIB_MapColor
*/
int X11DRV_DIB_MapColor( int *physMap, int nPhysMap, int phys, int oldcol )
{
int color;
if ((oldcol < nPhysMap) && (physMap[oldcol] == phys))
return oldcol;
for (color = 0; color < nPhysMap; color++)
if (physMap[color] == phys)
return color;
WARN("Strange color %08x\n", phys);
return 0;
}
/*********************************************************************
* X11DRV_DIB_GetNearestIndex
*
* Helper for X11DRV_DIB_GetDIBits.
* Returns the nearest colour table index for a given RGB.
* Nearest is defined by minimizing the sum of the squares.
*/
static INT X11DRV_DIB_GetNearestIndex(RGBQUAD *colormap, int numColors, BYTE r, BYTE g, BYTE b)
{
INT i, best = -1, diff, bestdiff = -1;
RGBQUAD *color;
for(color = colormap, i = 0; i < numColors; color++, i++) {
diff = (r - color->rgbRed) * (r - color->rgbRed) +
(g - color->rgbGreen) * (g - color->rgbGreen) +
(b - color->rgbBlue) * (b - color->rgbBlue);
if(diff == 0)
return i;
if(best == -1 || diff < bestdiff) {
best = i;
bestdiff = diff;
}
}
return best;
}
/***********************************************************************
* X11DRV_DIB_SetImageBits_1_Line
*
* Handles a single line of 1 bit data.
*/
static void X11DRV_DIB_SetImageBits_1_Line(DWORD dstwidth, int left, int *colors,
XImage *bmpImage, int h, const BYTE *bits)
{
BYTE pix, extra;
DWORD i, x;
if((extra = (left & 7)) != 0) {
left &= ~7;
dstwidth += extra;
}
bits += left >> 3;
/* FIXME: should avoid putting x<left pixels (minor speed issue) */
for (i = dstwidth/8, x = left; i > 0; i--)
{
pix = *bits++;
XPutPixel( bmpImage, x++, h, colors[pix >> 7] );
XPutPixel( bmpImage, x++, h, colors[(pix >> 6) & 1] );
XPutPixel( bmpImage, x++, h, colors[(pix >> 5) & 1] );
XPutPixel( bmpImage, x++, h, colors[(pix >> 4) & 1] );
XPutPixel( bmpImage, x++, h, colors[(pix >> 3) & 1] );
XPutPixel( bmpImage, x++, h, colors[(pix >> 2) & 1] );
XPutPixel( bmpImage, x++, h, colors[(pix >> 1) & 1] );
XPutPixel( bmpImage, x++, h, colors[pix & 1] );
}
pix = *bits;
switch(dstwidth & 7)
{
case 7: XPutPixel( bmpImage, x++, h, colors[pix >> 7] ); pix <<= 1;
case 6: XPutPixel( bmpImage, x++, h, colors[pix >> 7] ); pix <<= 1;
case 5: XPutPixel( bmpImage, x++, h, colors[pix >> 7] ); pix <<= 1;
case 4: XPutPixel( bmpImage, x++, h, colors[pix >> 7] ); pix <<= 1;
case 3: XPutPixel( bmpImage, x++, h, colors[pix >> 7] ); pix <<= 1;
case 2: XPutPixel( bmpImage, x++, h, colors[pix >> 7] ); pix <<= 1;
case 1: XPutPixel( bmpImage, x++, h, colors[pix >> 7] );
}
}
/***********************************************************************
* X11DRV_DIB_SetImageBits_1
*
* SetDIBits for a 1-bit deep DIB.
*/
static void X11DRV_DIB_SetImageBits_1( int lines, const BYTE *srcbits,
DWORD srcwidth, DWORD dstwidth, int left,
int *colors, XImage *bmpImage, DWORD linebytes)
{
int h;
if (lines > 0) {
for (h = lines-1; h >=0; h--) {
X11DRV_DIB_SetImageBits_1_Line(dstwidth, left, colors, bmpImage, h,
srcbits);
srcbits += linebytes;
}
} else {
lines = -lines;
for (h = 0; h < lines; h++) {
X11DRV_DIB_SetImageBits_1_Line(dstwidth, left, colors, bmpImage, h,
srcbits);
srcbits += linebytes;
}
}
}
/***********************************************************************
* X11DRV_DIB_GetImageBits_1
*
* GetDIBits for a 1-bit deep DIB.
*/
static void X11DRV_DIB_GetImageBits_1( int lines, BYTE *dstbits,
DWORD dstwidth, DWORD srcwidth,
RGBQUAD *colors, PALETTEENTRY *srccolors,
XImage *bmpImage, DWORD linebytes )
{
DWORD x;
int h;
BYTE *bits;
if (lines < 0 ) {
lines = -lines;
dstbits = dstbits + linebytes * (lines - 1);
linebytes = -linebytes;
}
bits = dstbits;
switch(bmpImage->depth) {
case 1:
/* ==== monochrome bitmap to monochrome dib ==== */
case 4:
/* ==== 4 colormap bitmap to monochrome dib ==== */
if (bmpImage->red_mask==0 && bmpImage->green_mask==0 && bmpImage->blue_mask==0 && srccolors)
{
PALETTEENTRY val;
for (h = lines - 1; h >= 0; h--) {
for (x = 0; x < dstwidth; x++) {
val = srccolors[XGetPixel(bmpImage, x, h)];
if (!(x&7)) *bits = 0;
*bits |= (X11DRV_DIB_GetNearestIndex(colors, 2,
val.peRed,
val.peGreen,
val.peBlue) << (7 - (x & 7)));
if ((x&7)==7) bits++;
}
bits = (dstbits += linebytes);
}
}
else goto notsupported;
break;
case 8:
/* ==== 8 colormap bitmap to monochrome dib ==== */
if ( bmpImage->red_mask==0 && bmpImage->green_mask==0 && bmpImage->blue_mask==0 && srccolors)
{
BYTE *srcpixel;
PALETTEENTRY val;
for( h = lines- 1; h >= 0; h-- ) {
srcpixel = bmpImage->data + (h*bmpImage->bytes_per_line);
for( x = 0; x < dstwidth; x++ ) {
if (!(x&7)) *bits = 0;
val = srccolors[(int)*srcpixel++];
*bits |= ( X11DRV_DIB_GetNearestIndex(colors, 2,
val.peRed,
val.peGreen,
val.peBlue) << (7-(x&7)) );
if ((x&7)==7) bits++;
}
bits = (dstbits += linebytes);
}
}
else goto notsupported;
break;
case 15:
{
LPWORD srcpixel;
WORD val;
/* ==== 555 BGR bitmap to monochrome dib ==== */
if (bmpImage->red_mask == 0x7c00 && bmpImage->blue_mask == 0x1f)
{
for( h = lines - 1; h >= 0; h--) {
srcpixel = (LPWORD)(bmpImage->data + h*bmpImage->bytes_per_line);
for( x = 0; x < dstwidth; x++) {
if (!(x&7)) *bits = 0;
val = *srcpixel++;
*bits |= (X11DRV_DIB_GetNearestIndex( colors, 2,
((val >> 7) & 0xf8) |
((val >> 12) & 0x7),
((val >> 2) & 0xf8) |
((val >> 7) & 0x3),
((val << 3) & 0xf8) |
((val >> 2) & 0x7) ) << (7-(x&7)) );
if ((x&7)==7) bits++;
}
bits = (dstbits += linebytes);
}
}
/* ==== 555 RGB bitmap to monochrome dib ==== */
else if (bmpImage->red_mask == 0x001f && bmpImage->blue_mask == 0xf800)
{
for( h = lines - 1; h >= 0; h--)
{
srcpixel = (LPWORD)(bmpImage->data + h*bmpImage->bytes_per_line);
for( x = 0; x < dstwidth; x++) {
if (!(x&1)) *bits = 0;
val = *srcpixel++;
*bits |= (X11DRV_DIB_GetNearestIndex( colors, 2,
((val << 3) & 0xf8) |
((val >> 2) & 0x7),
((val >> 2) & 0xf8) |
((val >> 7) & 0x3),
((val >> 7) & 0xf8) |
((val >> 12) & 0x7) ) << (7-(x&7)) );
if ((x&7)==7) bits++;
}
bits = (dstbits += linebytes);
}
}
else goto notsupported;
}
break;
case 16:
{
LPWORD srcpixel;
WORD val;
/* ==== 565 BGR bitmap to monochrome dib ==== */
if (bmpImage->red_mask == 0xf800 && bmpImage->blue_mask == 0x001f)
{
for( h = lines - 1; h >= 0; h--)
{
srcpixel = (LPWORD)(bmpImage->data + h*bmpImage->bytes_per_line);
for( x = 0; x < dstwidth; x++) {
if (!(x&7)) *bits = 0;
val = *srcpixel++;
*bits |= (X11DRV_DIB_GetNearestIndex( colors, 2,
((val >> 8) & 0xf8) |
((val >> 13) & 0x7),
((val >> 3) & 0xfc) |
((val >> 9) & 0x3),
((val << 3) & 0xf8) |
((val >> 2) & 0x7) ) << (7-(x&7)) );
if ((x&7)==7) bits++;
}
bits = (dstbits += linebytes);
}
}
/* ==== 565 RGB bitmap to monochrome dib ==== */
else if (bmpImage->red_mask == 0x001f && bmpImage->blue_mask == 0xf800)
{
for( h = lines - 1; h >= 0; h--)
{
srcpixel = (LPWORD)(bmpImage->data + h*bmpImage->bytes_per_line);
for( x = 0; x < dstwidth; x++) {
if (!(x&7)) *bits = 0;
val = *srcpixel++;
*bits |= (X11DRV_DIB_GetNearestIndex( colors, 2,
((val << 3) & 0xf8) |
((val >> 2) & 0x7),
((val >> 3) & 0xfc) |
((val >> 9) & 0x3),
((val >> 8) & 0xf8) |
((val >> 13) & 0x7) ) << (7-(x&7)) );
if ((x&7)==7) bits++;
}
bits = (dstbits += linebytes);
}
}
else goto notsupported;
}
break;
case 24:
case 32:
{
BYTE *srcpixel;
/* ==== 24/32 BGR bitmap to monochrome dib ==== */
if (bmpImage->red_mask == 0xff0000 && bmpImage->blue_mask == 0xff)
{
for (h = lines - 1; h >= 0; h--)
{
srcpixel = bmpImage->data + h*bmpImage->bytes_per_line;
for (x = 0; x < dstwidth; x++, srcpixel+=4) {
if (!(x&7)) *bits = 0;
*bits |= (X11DRV_DIB_GetNearestIndex(colors, 2, srcpixel[2] , srcpixel[1], srcpixel[0]) << (7-(x&7)) );
if ((x&7)==7) bits++;
}
bits = (dstbits += linebytes);
}
}
/* ==== 24/32 RGB bitmap to monochrome dib ==== */
else if (bmpImage->red_mask == 0xff && bmpImage->blue_mask == 0xff0000)
{
for (h = lines - 1; h >= 0; h--)
{
srcpixel = bmpImage->data + h*bmpImage->bytes_per_line;
for (x = 0; x < dstwidth; x++, srcpixel+=4) {
if (!(x & 7)) *bits = 0;
*bits |= (X11DRV_DIB_GetNearestIndex(colors, 2, srcpixel[0] , srcpixel[1], srcpixel[2]) << (7-(x&7)) );
if ((x & 7) == 7) bits++;
}
bits = (dstbits += linebytes);
}
}
else goto notsupported;
}
break;
default: /* ? bit bmp -> monochrome DIB */
notsupported:
{
unsigned long white = (1 << bmpImage->bits_per_pixel) - 1;
FIXME("from %d bit bitmap with mask R,G,B %x,%x,%x to 1 bit DIB\n",
bmpImage->bits_per_pixel, (int)bmpImage->red_mask,
(int)bmpImage->green_mask, (int)bmpImage->blue_mask );
for( h = lines - 1; h >= 0; h-- ) {
for( x = 0; x < dstwidth; x++ ) {
if (!(x&7)) *bits = 0;
*bits |= (XGetPixel( bmpImage, x, h) >= white)
<< (7 - (x&7));
if ((x&7)==7) bits++;
}
bits = (dstbits += linebytes);
}
}
break;
}
}
/***********************************************************************
* X11DRV_DIB_SetImageBits_4
*
* SetDIBits for a 4-bit deep DIB.
*/
static void X11DRV_DIB_SetImageBits_4( int lines, const BYTE *srcbits,
DWORD srcwidth, DWORD dstwidth, int left,
int *colors, XImage *bmpImage, DWORD linebytes)
{
DWORD i, x;
int h;
const BYTE *bits = srcbits + (left >> 1);
if(left & 1) {
left--;
dstwidth++;
}
if (lines > 0) {
for (h = lines-1; h >= 0; h--) {
for (i = dstwidth/2, x = left; i > 0; i--) {
BYTE pix = *bits++;
XPutPixel( bmpImage, x++, h, colors[pix >> 4] );
XPutPixel( bmpImage, x++, h, colors[pix & 0x0f] );
}
if (dstwidth & 1) XPutPixel( bmpImage, x, h, colors[*bits >> 4] );
srcbits += linebytes;
bits = srcbits + (left >> 1);
}
} else {
lines = -lines;
for (h = 0; h < lines; h++) {
for (i = dstwidth/2, x = left; i > 0; i--) {
BYTE pix = *bits++;
XPutPixel( bmpImage, x++, h, colors[pix >> 4] );
XPutPixel( bmpImage, x++, h, colors[pix & 0x0f] );
}
if (dstwidth & 1) XPutPixel( bmpImage, x, h, colors[*bits >> 4] );
srcbits += linebytes;
bits = srcbits + (left >> 1);
}
}
}
/***********************************************************************
* X11DRV_DIB_GetImageBits_4
*
* GetDIBits for a 4-bit deep DIB.
*/
static void X11DRV_DIB_GetImageBits_4( int lines, BYTE *dstbits,
DWORD srcwidth, DWORD dstwidth,
RGBQUAD *colors, PALETTEENTRY *srccolors,
XImage *bmpImage, DWORD linebytes )
{
DWORD x;
int h;
BYTE *bits;
LPBYTE srcpixel;
if (lines < 0 )
{
lines = -lines;
dstbits = dstbits + ( linebytes * (lines-1) );
linebytes = -linebytes;
}
bits = dstbits;
switch(bmpImage->depth) {
case 1:
/* ==== monochrome bitmap to 4 colormap dib ==== */
case 4:
/* ==== 4 colormap bitmap to 4 colormap dib ==== */
if (bmpImage->red_mask==0 && bmpImage->green_mask==0 && bmpImage->blue_mask==0 && srccolors)
{
PALETTEENTRY val;
for (h = lines-1; h >= 0; h--) {
for (x = 0; x < dstwidth; x++) {
if (!(x&1)) *bits = 0;
val = srccolors[XGetPixel(bmpImage, x, h)];
*bits |= (X11DRV_DIB_GetNearestIndex(colors, 16,
val.peRed,
val.peGreen,
val.peBlue) << (4-((x&1)<<2)));
if ((x&1)==1) bits++;
}
bits = (dstbits += linebytes);
}
}
else goto notsupported;
break;
case 8:
/* ==== 8 colormap bitmap to 4 colormap dib ==== */
if ( bmpImage->red_mask==0 && bmpImage->green_mask==0 && bmpImage->blue_mask==0 && srccolors)
{
PALETTEENTRY val;
for( h = lines - 1; h >= 0; h-- ) {
srcpixel = bmpImage->data + (h*bmpImage->bytes_per_line);
for( x = 0; x < dstwidth; x++ ) {
if (!(x&1)) *bits = 0;
val = srccolors[(int)*srcpixel++];
*bits |= ( X11DRV_DIB_GetNearestIndex(colors, 16,
val.peRed,
val.peGreen,
val.peBlue) << (4*(1-(x&1))) );
if ((x&1)==1) bits++;
}
bits = (dstbits += linebytes);
}
}
else goto notsupported;
break;
case 15:
{
LPWORD srcpixel;
WORD val;
/* ==== 555 BGR bitmap to 4 colormap dib ==== */
if (bmpImage->red_mask == 0x7c00 && bmpImage->blue_mask == 0x1f)
{
for( h = lines - 1; h >= 0; h--) {
srcpixel = (LPWORD)(bmpImage->data + h*bmpImage->bytes_per_line);
for( x = 0; x < dstwidth; x++) {
if (!(x&1)) *bits = 0;
val = *srcpixel++;
*bits |= (X11DRV_DIB_GetNearestIndex( colors, 16,
((val >> 7) & 0xf8) |
((val >> 12) & 0x7),
((val >> 2) & 0xf8) |
((val >> 7) & 0x3),
((val << 3) & 0xf8) |
((val >> 2) & 0x7) ) << ((1-(x&1))<<2) );
if ((x&1)==1) bits++;
}
bits = (dstbits += linebytes);
}
}
/* ==== 555 RGB bitmap to 4 colormap dib ==== */
else if (bmpImage->red_mask == 0x001f && bmpImage->blue_mask == 0x7c00)
{
for( h = lines - 1; h >= 0; h--)
{
srcpixel = (LPWORD)(bmpImage->data + h*bmpImage->bytes_per_line);
for( x = 0; x < dstwidth; x++) {
if (!(x&1)) *bits = 0;
val = *srcpixel++;
*bits |= (X11DRV_DIB_GetNearestIndex( colors, 16,
((val << 3) & 0xf8) |
((val >> 2) & 0x7),
((val >> 2) & 0xfc) |
((val >> 7) & 0x3),
((val >> 7) & 0xf8) |
((val >> 12) & 0x7) ) << ((1-(x&1))<<2) );
if ((x&1)==1) bits++;
}
bits = (dstbits += linebytes);
}
}
else goto notsupported;
}
break;
case 16:
{
LPWORD srcpixel;
WORD val;
/* ==== 565 BGR bitmap to 4 colormap dib ==== */
if (bmpImage->red_mask == 0xf800 && bmpImage->blue_mask == 0x001f)
{
for( h = lines - 1; h >= 0; h--)
{
srcpixel = (LPWORD)(bmpImage->data + h*bmpImage->bytes_per_line);
for( x = 0; x < dstwidth; x++) {
if (!(x&1)) *bits = 0;
val = *srcpixel++;
*bits |= (X11DRV_DIB_GetNearestIndex( colors, 16,
((val >> 8) & 0xf8) |
((val >> 13) & 0x7),
((val >> 3) & 0xfc) |
((val >> 9) & 0x3),
((val << 3) & 0xf8) |
((val >> 2) & 0x7) ) << ((1-(x&1))<<2) );
if ((x&1)==1) bits++;
}
bits = (dstbits += linebytes);
}
}
/* ==== 565 RGB bitmap to 4 colormap dib ==== */
else if (bmpImage->red_mask == 0x001f && bmpImage->blue_mask == 0xf800)
{
for( h = lines - 1; h >= 0; h--)
{
srcpixel = (LPWORD)(bmpImage->data + h*bmpImage->bytes_per_line);
for( x = 0; x < dstwidth; x++) {
if (!(x&1)) *bits = 0;
val = *srcpixel++;
*bits |= (X11DRV_DIB_GetNearestIndex( colors, 16,
((val << 3) & 0xf8) |
((val >> 2) & 0x7),
((val >> 3) & 0xfc) |
((val >> 9) & 0x3),
((val >> 8) & 0xf8) |
((val >> 13) & 0x7) ) << ((1-(x&1))<<2) );
if ((x&1)==1) bits++;
}
bits = (dstbits += linebytes);
}
}
else goto notsupported;
}
break;
case 24:
case 32:
{
BYTE *srcpixel;
/* ==== 24/32 BGR bitmap to 4 colormap dib ==== */
if (bmpImage->red_mask == 0xff0000 && bmpImage->blue_mask == 0xff)
{
for (h = lines - 1; h >= 0; h--)
{
srcpixel = bmpImage->data + h*bmpImage->bytes_per_line;
for (x = 0; x < dstwidth; x+=2, srcpixel+=8) /* 2 pixels at a time */
*bits++ = (X11DRV_DIB_GetNearestIndex(colors, 16, srcpixel[2] , srcpixel[1], srcpixel[0]) << 4) |
X11DRV_DIB_GetNearestIndex(colors, 16, srcpixel[6] , srcpixel[5], srcpixel[4]);
bits = (dstbits += linebytes);
}
}
/* ==== 24/32 RGB bitmap to 4 colormap dib ==== */
else if (bmpImage->red_mask == 0xff && bmpImage->blue_mask == 0xff0000)
{
for (h = lines - 1; h >= 0; h--)
{
srcpixel = bmpImage->data + h*bmpImage->bytes_per_line;
for (x = 0; x < dstwidth; x+=2, srcpixel+=8) /* 2 pixels at a time */
*bits++ = (X11DRV_DIB_GetNearestIndex(colors, 16, srcpixel[0] , srcpixel[1], srcpixel[2]) << 4) |
X11DRV_DIB_GetNearestIndex(colors, 16, srcpixel[4] , srcpixel[5], srcpixel[6]);
bits = (dstbits += linebytes);
}
}
else goto notsupported;
}
break;
default: /* ? bit bmp -> 4 bit DIB */
notsupported:
FIXME("from %d bit bitmap with mask R,G,B %x,%x,%x to 4 bit DIB\n",
bmpImage->bits_per_pixel, (int)bmpImage->red_mask,
(int)bmpImage->green_mask, (int)bmpImage->blue_mask );
for (h = lines-1; h >= 0; h--) {
for (x = 0; x < dstwidth-1; x += 2)
{
*bits++ = (X11DRV_DIB_MapColor((int *)colors, 16, XGetPixel( bmpImage, x, h ), 0) << 4)
| (X11DRV_DIB_MapColor((int *)colors, 16, XGetPixel( bmpImage, x+1, h ), 0) & 0x0f);
}
if (dstwidth & 1)
*bits = (X11DRV_DIB_MapColor((int *)colors, 16, XGetPixel( bmpImage, x, h ), 0) << 4);
bits = (dstbits += linebytes);
}
break;
}
}
/***********************************************************************
* X11DRV_DIB_SetImageBits_RLE4
*
* SetDIBits for a 4-bit deep compressed DIB.
*/
static void X11DRV_DIB_SetImageBits_RLE4( int lines, const BYTE *bits,
DWORD width, DWORD dstwidth,
int left, int *colors,
XImage *bmpImage )
{
int x = 0, y = lines - 1, c, length;
const BYTE *begin = bits;
while (y >= 0)
{
length = *bits++;
if (length) { /* encoded */
c = *bits++;
while (length--) {
if (x >= width) break;
XPutPixel(bmpImage, x++, y, colors[c >> 4]);
if (!length--) break;
if (x >= width) break;
XPutPixel(bmpImage, x++, y, colors[c & 0xf]);
}
} else {
length = *bits++;
switch (length)
{
case RLE_EOL:
x = 0;
y--;
break;
case RLE_END:
return;
case RLE_DELTA:
x += *bits++;
y -= *bits++;
break;
default: /* absolute */
while (length--) {
c = *bits++;
if (x < width) XPutPixel(bmpImage, x++, y, colors[c >> 4]);
if (!length--) break;
if (x < width) XPutPixel(bmpImage, x++, y, colors[c & 0xf]);
}
if ((bits - begin) & 1)
bits++;
}
}
}
}
/***********************************************************************
* X11DRV_DIB_SetImageBits_8
*
* SetDIBits for an 8-bit deep DIB.
*/
static void X11DRV_DIB_SetImageBits_8( int lines, const BYTE *srcbits,
DWORD srcwidth, DWORD dstwidth, int left,
const int *colors, XImage *bmpImage,
DWORD linebytes )
{
DWORD x;
int h, color;
const BYTE *bits;
dstwidth += left;
if (lines < 0 )
{
lines = -lines;
srcbits = srcbits + ( linebytes * (lines-1) );
linebytes = -linebytes;
}
bits = srcbits + left;
switch (bmpImage->depth) {
case 15:
case 16:
#if defined(__i386__) && defined(__GNUC__)
/* Some X servers might have 32 bit/ 16bit deep pixel */
if (lines && (dstwidth!=left) && (bmpImage->bits_per_pixel == 16))
{
for (h = lines ; h--; ) {
int _cl1,_cl2; /* temp outputs for asm below */
/* Borrowed from DirectDraw */
__asm__ __volatile__(
"xor %%eax,%%eax\n"
"cld\n"
"1:\n"
" lodsb\n"
" movw (%%edx,%%eax,4),%%ax\n"
" stosw\n"
" xor %%eax,%%eax\n"
" loop 1b\n"
:"=S" (bits), "=D" (_cl1), "=c" (_cl2)
:"S" (bits),
"D" (bmpImage->data+h*bmpImage->bytes_per_line+left*2),
"c" (dstwidth-left),
"d" (colors)
:"eax", "cc", "memory"
);
bits = (srcbits += linebytes) + left;
}
return;
}
break;
#endif
case 24:
#if defined(__i386__) && defined(__GNUC__)
if (lines && (dstwidth!=left) && (bmpImage->bits_per_pixel == 32))
{
for (h = lines ; h--; ) {
int _cl1,_cl2; /* temp outputs for asm below */
/* Borrowed from DirectDraw */
__asm__ __volatile__(
"xor %%eax,%%eax\n"
"cld\n"
"1:\n"
" lodsb\n"
" movl (%%edx,%%eax,4),%%eax\n"
" stosl\n"
" xor %%eax,%%eax\n"
" loop 1b\n"
:"=S" (bits), "=D" (_cl1), "=c" (_cl2)
:"S" (bits),
"D" (bmpImage->data+h*bmpImage->bytes_per_line+left*4),
"c" (dstwidth-left),
"d" (colors)
:"eax", "cc", "memory"
);
bits = (srcbits += linebytes) + left;
}
return;
}
break;
#endif
default:
break; /* use slow generic case below */
}
for (h = lines - 1; h >= 0; h--) {
for (x = left; x < dstwidth; x++, bits++) {
color = colors[*bits];
XPutPixel( bmpImage, x, h, colors[*bits] );
}
bits = (srcbits += linebytes) + left;
}
}
/***********************************************************************
* X11DRV_DIB_GetImageBits_8
*
* GetDIBits for an 8-bit deep DIB.
*/
static void X11DRV_DIB_GetImageBits_8( int lines, BYTE *dstbits,
DWORD srcwidth, DWORD dstwidth,
RGBQUAD *colors, PALETTEENTRY *srccolors,
XImage *bmpImage, DWORD linebytes )
{
DWORD x;
int h;
BYTE *bits;
if (lines < 0 )
{
lines = -lines;
dstbits = dstbits + ( linebytes * (lines-1) );
linebytes = -linebytes;
}
bits = dstbits;
/*
Hack for now
This condition is true when GetImageBits has been called by UpdateDIBSection.
For now, GetNearestIndex is too slow to support 256 colormaps, so we'll just use for
for GetDIBits calls. (In somes cases, in a updateDIBSection, the returned colors are bad too)
*/
if (!srccolors) goto updatesection;
switch(bmpImage->depth) {
case 1:
/* ==== monochrome bitmap to 8 colormap dib ==== */
case 4:
/* ==== 4 colormap bitmap to 8 colormap dib ==== */
if (bmpImage->red_mask==0 && bmpImage->green_mask==0 && bmpImage->blue_mask==0 && srccolors)
{
PALETTEENTRY val;
for (h = lines - 1; h >= 0; h--) {
for (x = 0; x < dstwidth; x++) {
val = srccolors[XGetPixel(bmpImage, x, h)];
*bits++ = X11DRV_DIB_GetNearestIndex(colors, 256, val.peRed,
val.peGreen, val.peBlue);
}
bits = (dstbits += linebytes);
}
}
else goto notsupported;
break;
case 8:
/* ==== 8 colormap bitmap to 8 colormap dib ==== */
if (bmpImage->red_mask==0 && bmpImage->green_mask==0 && bmpImage->blue_mask==0 && srccolors)
{
BYTE *srcpixel;
PALETTEENTRY val;
for (h = lines - 1; h >= 0; h--) {
srcpixel = bmpImage->data + h*bmpImage->bytes_per_line;
for (x = 0; x < dstwidth; x++) {
val = srccolors[(int)*srcpixel++];
*bits++ = X11DRV_DIB_GetNearestIndex(colors, 256, val.peRed,
val.peGreen, val.peBlue);
}
bits = (dstbits += linebytes);
}
}
else goto notsupported;
break;
case 15:
{
LPWORD srcpixel;
WORD val;
/* ==== 555 BGR bitmap to 8 colormap dib ==== */
if (bmpImage->red_mask == 0x7c00 && bmpImage->blue_mask == 0x001f)
{
for( h = lines - 1; h >= 0; h--)
{
srcpixel = (LPWORD)(bmpImage->data + h*bmpImage->bytes_per_line);
for( x = 0; x < dstwidth; x++ )
{
val = *srcpixel++;
*bits++ = X11DRV_DIB_GetNearestIndex( colors, 256,
((val >> 7) & 0xf8) |
((val >> 12) & 0x7),
((val >> 2) & 0xf8) |
((val >> 7) & 0x3),
((val << 3) & 0xf8) |
((val >> 2) & 0x7) );
}
bits = (dstbits += linebytes);
}
}
/* ==== 555 RGB bitmap to 8 colormap dib ==== */
else if (bmpImage->red_mask == 0x001f && bmpImage->blue_mask == 0x7c00)
{
for( h = lines - 1; h >= 0; h--)
{
srcpixel = (LPWORD)(bmpImage->data + h*bmpImage->bytes_per_line);
for( x = 0; x < dstwidth; x++ )
{
val = *srcpixel++;
*bits++ = X11DRV_DIB_GetNearestIndex( colors, 256,
((val << 3) & 0xf8) |
((val >> 2) & 0x7),
((val >> 2) & 0xf8) |
((val >> 7) & 0x3),
((val >> 7) & 0xf8) |
((val >> 12) & 0x7) );
}
bits = (dstbits += linebytes);
}
}
else goto notsupported;
}
break;
case 16:
{
LPWORD srcpixel;
WORD val;
/* ==== 565 BGR bitmap to 8 colormap dib ==== */
if (bmpImage->red_mask == 0xf800 && bmpImage->blue_mask == 0x001f)
{
for( h = lines - 1; h >= 0; h--)
{
srcpixel = (LPWORD)(bmpImage->data + h*bmpImage->bytes_per_line);
for( x = 0; x < dstwidth; x++ )
{
val = *srcpixel++;
*bits++ = X11DRV_DIB_GetNearestIndex( colors, 256,
((val >> 8) & 0xf8) |
((val >> 13) & 0x7),
((val >> 3) & 0xfc) |
((val >> 9) & 0x3),
((val << 3) & 0xf8) |
((val >> 2) & 0x7) );
}
bits = (dstbits += linebytes);
}
}
/* ==== 565 RGB bitmap to 8 colormap dib ==== */
else if (bmpImage->red_mask == 0x001f && bmpImage->blue_mask == 0xf800)
{
for( h = lines - 1; h >= 0; h--)
{
srcpixel = (LPWORD)(bmpImage->data + h*bmpImage->bytes_per_line);
for( x = 0; x < dstwidth; x++ )
{
val = *srcpixel++;
*bits++ = X11DRV_DIB_GetNearestIndex( colors, 256,
((val << 3) & 0xf8) |
((val >> 2) & 0x7),
((val >> 3) & 0x00fc) |
((val >> 9) & 0x3),
((val >> 8) & 0x00f8) |
((val >> 13) & 0x7) );
}
bits = (dstbits += linebytes);
}
}
else goto notsupported;
}
break;
case 24:
case 32:
{
BYTE *srcpixel;
/* ==== 24/32 BGR bitmap to 8 colormap dib ==== */
if (bmpImage->red_mask == 0xff0000 && bmpImage->blue_mask == 0xff)
{
for (h = lines - 1; h >= 0; h--)
{
srcpixel = bmpImage->data + h*bmpImage->bytes_per_line;
for (x = 0; x < dstwidth; x++, srcpixel+=4)
*bits++ = X11DRV_DIB_GetNearestIndex(colors, 256,
srcpixel[2] , srcpixel[1], *srcpixel);
bits = (dstbits += linebytes);
}
}
/* ==== 24/32 RGB bitmap to 8 colormap dib ==== */
else if (bmpImage->red_mask == 0xff && bmpImage->blue_mask == 0xff0000)
{
for (h = lines - 1; h >= 0; h--)
{
srcpixel = bmpImage->data + h*bmpImage->bytes_per_line;
for (x = 0; x < dstwidth; x++, srcpixel+=4)
*bits++ = X11DRV_DIB_GetNearestIndex(colors, 256,
*srcpixel, srcpixel[1], srcpixel[2]);
bits = (dstbits += linebytes);
}
}
else goto notsupported;
}
break;
default: /* ? bit bmp -> 8 bit DIB */
notsupported:
FIXME("from %d bit bitmap with mask R,G,B %x,%x,%x to 8 bit DIB\n",
bmpImage->depth, (int)bmpImage->red_mask,
(int)bmpImage->green_mask, (int)bmpImage->blue_mask );
updatesection:
for (h = lines - 1; h >= 0; h--) {
for (x = 0; x < dstwidth; x++, bits++) {
*bits = X11DRV_DIB_MapColor((int *)colors, 256,
XGetPixel( bmpImage, x, h ), *bits);
}
bits = (dstbits += linebytes);
}
break;
}
}
/***********************************************************************
* X11DRV_DIB_SetImageBits_RLE8
*
* SetDIBits for an 8-bit deep compressed DIB.
*
* This function rewritten 941113 by James Youngman. WINE blew out when I
* first ran it because my desktop wallpaper is a (large) RLE8 bitmap.
*
* This was because the algorithm assumed that all RLE8 bitmaps end with the
* 'End of bitmap' escape code. This code is very much laxer in what it
* allows to end the expansion. Possibly too lax. See the note by
* case RleDelta. BTW, MS's documentation implies that a correct RLE8
* bitmap should end with RleEnd, but on the other hand, software exists
* that produces ones that don't and Windows 3.1 doesn't complain a bit
* about it.
*
* (No) apologies for my English spelling. [Emacs users: c-indent-level=4].
* James A. Youngman <mbcstjy@afs.man.ac.uk>
* [JAY]
*/
static void X11DRV_DIB_SetImageBits_RLE8( int lines, const BYTE *bits,
DWORD width, DWORD dstwidth,
int left, int *colors,
XImage *bmpImage )
{
int x; /* X-positon on each line. Increases. */
int y; /* Line #. Starts at lines-1, decreases */
const BYTE *pIn = bits; /* Pointer to current position in bits */
BYTE length; /* The length pf a run */
BYTE escape_code; /* See enum Rle8_EscapeCodes.*/
/*
* Note that the bitmap data is stored by Windows starting at the
* bottom line of the bitmap and going upwards. Within each line,
* the data is stored left-to-right. That's the reason why line
* goes from lines-1 to 0. [JAY]
*/
x = 0;
y = lines - 1;
while (y >= 0)
{
length = *pIn++;
/*
* If the length byte is not zero (which is the escape value),
* We have a run of length pixels all the same colour. The colour
* index is stored next.
*
* If the length byte is zero, we need to read the next byte to
* know what to do. [JAY]
*/
if (length != 0)
{
/*
* [Run-Length] Encoded mode
*/
int color = colors[*pIn++];
while (length-- && x < dstwidth) XPutPixel(bmpImage, x++, y, color);
}
else
{
/*
* Escape codes (may be an absolute sequence though)
*/
escape_code = (*pIn++);
switch(escape_code)
{
case RLE_EOL:
x = 0;
y--;
break;
case RLE_END:
/* Not all RLE8 bitmaps end with this code. For
* example, Paint Shop Pro produces some that don't.
* That's (I think) what caused the previous
* implementation to fail. [JAY]
*/
return;
case RLE_DELTA:
x += (*pIn++);
y -= (*pIn++);
break;
default: /* switch to absolute mode */
length = escape_code;
while (length--)
{
int color = colors[*pIn++];
if (x >= dstwidth)
{
pIn += length;
break;
}
XPutPixel(bmpImage, x++, y, color);
}
/*
* If you think for a moment you'll realise that the
* only time we could ever possibly read an odd
* number of bytes is when there is a 0x00 (escape),
* a value >0x02 (absolute mode) and then an odd-
* length run. Therefore this is the only place we
* need to worry about it. Everywhere else the
* bytes are always read in pairs. [JAY]
*/
if (escape_code & 1) pIn++; /* Throw away the pad byte. */
break;
} /* switch (escape_code) : Escape sequence */
}
}
}
/***********************************************************************
* X11DRV_DIB_SetImageBits_16
*
* SetDIBits for a 16-bit deep DIB.
*/
static void X11DRV_DIB_SetImageBits_16( int lines, const BYTE *srcbits,
DWORD srcwidth, DWORD dstwidth, int left,
DC *dc, DWORD rSrc, DWORD gSrc, DWORD bSrc,
XImage *bmpImage, DWORD linebytes )
{
DWORD x;
int h;
if (lines < 0 )
{
lines = -lines;
srcbits = srcbits + ( linebytes * (lines-1));
linebytes = -linebytes;
}
switch ( bmpImage->depth )
{
case 15:
/* using same format as XImage */
if (rSrc == bmpImage->red_mask && gSrc == bmpImage->green_mask && bSrc == bmpImage->blue_mask)
for (h = lines - 1; h >= 0; h--, srcbits += linebytes)
memcpy ( bmpImage->data + h * bmpImage->bytes_per_line + left*2, srcbits + left*2, dstwidth*2 );
else /* We need to do a conversion from a 565 dib */
{
LPDWORD dstpixel, ptr = (LPDWORD)(srcbits + left*2);
DWORD val;
int div = dstwidth % 2;
for (h = lines - 1; h >= 0; h--) {
dstpixel = (LPDWORD) (bmpImage->data + h * bmpImage->bytes_per_line + left*2);
for (x = 0; x < dstwidth/2; x++) { /* Do 2 pixels at a time */
val = *ptr++;
*dstpixel++ = ((val >> 1) & 0x7fe07fe0) | (val & 0x001f001f); /* Red & Green & Blue */
}
if (div != 0) /* Odd width? */
*dstpixel = ((*(WORD *)ptr >> 1) & 0x7fe0) | (*(WORD *)ptr & 0x001f);
ptr = (LPDWORD) ((srcbits += linebytes) + left*2);
}
}
break;
case 16:
/* using same format as XImage */
if (rSrc == bmpImage->red_mask && gSrc == bmpImage->green_mask && bSrc == bmpImage->blue_mask)
for (h = lines - 1; h >= 0; h--, srcbits += linebytes)
memcpy ( bmpImage->data + h * bmpImage->bytes_per_line + left*2, srcbits + left*2, dstwidth*2 );
else /* We need to do a conversion from a 555 dib */
{
LPDWORD dstpixel, ptr = (LPDWORD)(srcbits + left*2);
DWORD val;
int div = dstwidth % 2;
for (h = lines - 1; h >= 0; h--) {
dstpixel = (LPDWORD) (bmpImage->data + h * bmpImage->bytes_per_line + left*2);
for (x = 0; x < dstwidth/2; x++) { /* Do 2 pixels at a time */
val = *ptr++;
*dstpixel++ = ((val << 1) & 0xffc0ffc0) | ((val >> 4) & 0x00200020) | /* Red & Green */
(val & 0x001f001f); /* Blue */
}
if (div != 0) /* Odd width? */
*dstpixel = ((*(WORD *)ptr << 1) & 0xffc0) | ((*(WORD *)ptr >> 4) & 0x0020)
| (*(WORD *)ptr & 0x001f);
ptr = (LPDWORD) ((srcbits += linebytes) + left*2);
}
}
break;
case 24:
case 32:
{
DWORD *dstpixel;
LPWORD ptr = (LPWORD)srcbits + left;
DWORD val;
if (bmpImage->red_mask == 0xff0000 && bmpImage->blue_mask == 0xff)
{
if ((rSrc == 0xF800) && (gSrc == 0x07E0) && (bSrc == 0x001F)) {
/* ==== 555 RGB dib to 24/32 RGB bitmap ==== */
for (h = lines - 1; h >= 0; h--) {
dstpixel = (DWORD *) (bmpImage->data + h * bmpImage->bytes_per_line + left*4);
for (x = 0; x < dstwidth; x++) {
val = *ptr++;
*dstpixel++ = ((val << 8) & 0xF80000) | /* Red */
((val << 5) & 0x00FC00) | /* Green */
((val << 3) & 0x0000FF); /* Blue */
}
ptr = (LPWORD)(srcbits += linebytes) + left;
}
} else {
/* ==== 555 BGR dib to 24/32 BGR bitmap ==== */
for (h = lines - 1; h >= 0; h--) {
dstpixel = (DWORD *) (bmpImage->data + h * bmpImage->bytes_per_line + left*4);
for (x = 0; x < dstwidth; x++) {
val = *ptr++;
*dstpixel++ = ((val << 9) & 0xf80000) | ((val << 4) & 0x070000) | /* Red */
((val << 6) & 0x00f800) | ((val << 1) & 0x000700) | /* Green */
((val << 3) & 0x0000f8) | ((val >> 2) & 0x000007); /* Blue */
}
ptr = (LPWORD)(srcbits += linebytes) + left;
}
}
}
/* ==== 555 BGR dib to 24/32 RGB bitmap ==== */
else if (bmpImage->red_mask == 0xff && bmpImage->blue_mask == 0xff0000)
{
for (h = lines - 1; h >= 0; h--) {
dstpixel = (DWORD *) (bmpImage->data + h * bmpImage->bytes_per_line + left*4);
for (x = 0; x < dstwidth; x++) {
val = *ptr++;
*dstpixel++ = ((val >> 7) & 0x0000f8) | ((val >> 12) & 0x000007) | /* Red */
((val << 6) & 0x00f800) | ((val << 1) & 0x000700) | /* Green */
((val << 19) & 0xf80000) | ((val >> 14) & 0x070000); /* Blue */
}
ptr = (LPWORD)(srcbits += linebytes) + left;
}
}
}
break;
case 1:
case 4:
case 8:
{
LPWORD ptr = (LPWORD)srcbits + left;
WORD val;
int sc1, sc2;
/* Set color scaling values */
if ( rSrc == 0x7c00 ) { sc1 = 7; sc2 = 2; } /* 555 dib */
else { sc1 = 8; sc2 = 3; } /* 565 dib */
for (h = lines - 1; h >= 0; h--) {
for (x = left; x < dstwidth+left; x++) {
val = *ptr++;
XPutPixel( bmpImage, x, h,
X11DRV_PALETTE_ToPhysical(dc, RGB(((val & rSrc) >> sc1), /* Red */
((val & gSrc) >> sc2), /* Green */
((val & bSrc) << 3)))); /* Blue */
}
ptr = (LPWORD) (srcbits += linebytes) + left;
}
}
break;
default:
FIXME("16 bit DIB %d bit bitmap\n", bmpImage->bits_per_pixel);
break;
}
}
/***********************************************************************
* X11DRV_DIB_GetImageBits_16
*
* GetDIBits for an 16-bit deep DIB.
*/
static void X11DRV_DIB_GetImageBits_16( int lines, BYTE *dstbits,
DWORD dstwidth, DWORD srcwidth,
PALETTEENTRY *srccolors,
DWORD rDst, DWORD gDst, DWORD bDst,
XImage *bmpImage, DWORD dibpitch )
{
DWORD x;
int h, rsc, gsc;
DWORD linebytes = dibpitch;
if (lines < 0 )
{
lines = -lines;
dstbits = dstbits + ( linebytes * (lines-1));
linebytes = -linebytes;
}
/* Set color scaling values */
if ( rDst == 0x7c00 ) { rsc = 7; gsc = 2; } /* 555 dib */
else { rsc = 8; gsc = 3; } /* 565 dib */
switch ( bmpImage->depth )
{
case 15:
/* using same format as XImage */
if (rDst == bmpImage->red_mask && bDst == bmpImage->blue_mask)
for (h = lines - 1; h >= 0; h--, dstbits += linebytes)
memcpy( dstbits, bmpImage->data + h*bmpImage->bytes_per_line, srcwidth*2 );
/* reversed format (BGR <=> RGB) */
else if (rDst == bmpImage->blue_mask && bDst == bmpImage->red_mask)
{
LPDWORD srcpixel, ptr = (LPDWORD)dstbits;
DWORD val;
int div = srcwidth % 2;
for (h = lines - 1; h >= 0; h--) {
srcpixel = (LPDWORD) (bmpImage->data + h * bmpImage->bytes_per_line);
for (x = 0; x < srcwidth/2; x++) { /* Do 2 pixels at a time */
val = *srcpixel++;
*ptr++ = ((val << 10) & 0xf800f800) | (val & 0x03e003e0) | /* Red & Green */
((val >> 10) & 0x001f001f); /* Blue */
}
if (div != 0) /* Odd width? */
*ptr = ((*(WORD *)srcpixel << 1) & 0xffc0) | ((*(WORD *)srcpixel >> 4) & 0x0020) |
(*(WORD *)srcpixel & 0x001f);
ptr = (LPDWORD)(dstbits += linebytes);
}
}
else goto notsupported;
break;
case 16:
{
LPDWORD srcpixel, ptr = (LPDWORD)dstbits;
DWORD val;
int div = srcwidth % 2;
/* using same format as XImage */
if (rDst == bmpImage->red_mask && bDst == bmpImage->blue_mask)
for (h = lines - 1; h >= 0; h--, dstbits += linebytes)
memcpy( dstbits, bmpImage->data + h*bmpImage->bytes_per_line, srcwidth*2 );
/* ==== 565 BGR bitmap to 555 BGR dib ==== */
else if (bmpImage->red_mask == 0xf800 && bmpImage->blue_mask == 0x001f &&
rDst == 0x7c00 && bDst == 0x001f)
{
for (h = lines - 1; h >= 0; h--) {
srcpixel = (LPDWORD) (bmpImage->data + h * bmpImage->bytes_per_line);
for (x = 0; x < srcwidth/2; x++) { /* Do 2 pixels at a time */
val = *srcpixel++;
*ptr++ = ((val >> 1) & 0x7fe07fe0) | /* Red & Green */
(val & 0x001f001f); /* Blue */
}
if (div != 0) /* Odd width? */
*ptr = ((*(WORD *)srcpixel >> 1) & 0x7fe0) | (*(WORD *)srcpixel & 0x001f);
ptr = (LPDWORD) (dstbits += linebytes);
}
}
/* ==== 565 RGB bitmap to 555 BGR dib ==== */
else if (bmpImage->red_mask == 0x001f && bmpImage->blue_mask == 0xf800 &&
rDst == 0x7c00 && bDst == 0x001f)
{
for (h = lines - 1; h >= 0; h--) {
srcpixel = (LPDWORD) (bmpImage->data + h * bmpImage->bytes_per_line);
for (x = 0; x < srcwidth/2; x++) { /* Do 2 pixels at a time */
val = *srcpixel++;
*ptr++ = ((val << 10) & 0x7c007c00) | ((val >> 1) & 0x03e003e0) | /* Red & Green */
((val >> 11) & 0x001f001f); /* Blue */
}
if (div != 0) /* Odd width? */
*ptr = ((*(WORD *)srcpixel >> 1) & 0x7fe0) | (*(WORD *)srcpixel & 0x001f);
ptr = (LPDWORD) (dstbits += linebytes);
}
}
else goto notsupported;
}
break;
case 24:
case 32:
{
DWORD *srcpixel;
LPWORD ptr = (LPWORD)dstbits;
DWORD val;
/* ==== 24/32 BGR bitmap ==== */
if (bmpImage->red_mask == 0xff0000 && bmpImage->blue_mask == 0xff)
{
int rsc2 = 16-rsc, gsc2 = 8-gsc;
for (h = lines - 1; h >= 0; h--) {
srcpixel = (DWORD *) (bmpImage->data + h * bmpImage->bytes_per_line);
for (x = 0; x < srcwidth; x++, ptr++) {
val = *srcpixel++;
*ptr = ((val >> rsc2) & rDst) |
((val >> gsc2) & gDst) |
((val >> 3) & bDst);
}
ptr = (LPWORD)(dstbits += linebytes);
}
}
/* ==== 24/32 RGB bitmap ==== */
else if (bmpImage->red_mask == 0xff && bmpImage->blue_mask == 0xff0000)
{
int gsc2 = 8-gsc;
for (h = lines - 1; h >= 0; h--) {
srcpixel = (DWORD *) (bmpImage->data + h * bmpImage->bytes_per_line);
for (x = 0; x < srcwidth; x++, ptr++) {
val = *srcpixel++;
*ptr = ((val << rsc) & rDst) |
((val >> gsc2) & gDst) |
((val >> 19) & bDst);
}
ptr = (LPWORD) (dstbits += linebytes);
}
}
else goto notsupported;
}
break;
case 1:
/* ==== monochrome bitmap ==== */
case 4:
/* ==== 4 colormap bitmap ==== */
if (bmpImage->red_mask==0 && bmpImage->green_mask==0 && bmpImage->blue_mask==0 && srccolors)
{
LPWORD ptr = (LPWORD)dstbits;
PALETTEENTRY val;
for (h = lines - 1; h >= 0; h--) {
for (x = 0; x < dstwidth; x++) {
val = srccolors[XGetPixel(bmpImage, x, h)];
*ptr++ = ((val.peRed << rsc) & rDst) |
((val.peGreen << gsc) & gDst) |
((val.peBlue >> 3) & bDst);
}
ptr = (LPWORD)(dstbits += linebytes);
}
}
else goto notsupported;
break;
case 8:
/* ==== 8 colormap bitmap ==== */
if (bmpImage->red_mask==0 && bmpImage->green_mask==0 && bmpImage->blue_mask==0 && srccolors)
{
LPWORD ptr = (LPWORD)dstbits;
BYTE *srcpixel;
PALETTEENTRY val;
for (h = lines - 1; h >= 0; h--) {
srcpixel = bmpImage->data + h*bmpImage->bytes_per_line;
for (x = 0; x < dstwidth; x++) {
val = srccolors[(int)*srcpixel++];
*ptr++ = ((val.peRed << rsc) & rDst) |
((val.peGreen << gsc) & gDst) |
((val.peBlue >> 3) & bDst);
}
ptr = (LPWORD)(dstbits += linebytes);
}
}
else goto notsupported;
break;
default:
notsupported:
{
BYTE r,g, b;
LPWORD ptr = (LPWORD)dstbits;
FIXME("from %d bit bitmap with mask R,G,B %lx,%lx,%lx to 16 bit DIB %lx,%lx,%lx\n",
bmpImage->depth, bmpImage->red_mask,
bmpImage->green_mask, bmpImage->blue_mask,
rDst, gDst, bDst);
for (h = lines - 1; h >= 0; h--)
{
for (x = 0; x < dstwidth; x++, ptr++)
{
COLORREF pixel = X11DRV_PALETTE_ToLogical( XGetPixel( bmpImage, x, h ) );
r = (BYTE) GetRValue(pixel);
g = (BYTE) GetGValue(pixel);
b = (BYTE) GetBValue(pixel);
*ptr = ( ((r << rsc) & rDst) | ((g << gsc) & gDst) | ((b >> 3) & bDst) );
}
ptr = (LPWORD) (dstbits += linebytes);
}
}
break;
}
}
/***********************************************************************
* X11DRV_DIB_SetImageBits_24
*
* SetDIBits for a 24-bit deep DIB.
*/
static void X11DRV_DIB_SetImageBits_24( int lines, const BYTE *srcbits,
DWORD srcwidth, DWORD dstwidth, int left,
DC *dc, XImage *bmpImage, DWORD linebytes )
{
DWORD x;
int h;
if (lines < 0 )
{
lines = -lines;
srcbits = srcbits + linebytes * (lines - 1);
linebytes = -linebytes;
}
switch ( bmpImage->depth )
{
case 24:
{
if (bmpImage->bits_per_pixel == 24) {
int dstlinebytes = linebytes;
BYTE *dstpixel;
BYTE *ptr = (BYTE *)(srcbits+left*3);
if (dstlinebytes < 0 ) dstlinebytes = -dstlinebytes;
dstpixel = bmpImage->data + lines*dstlinebytes + left*3;
for(h = lines ; h-- ; ) {
dstpixel-=dstlinebytes;
memcpy(dstpixel,ptr,dstwidth*3);
ptr +=linebytes;
}
break;
}
}
case 32:
{
if( bmpImage->blue_mask == 0xff && bmpImage->red_mask == 0xff0000 ) /* packed BGR to unpacked BGR */
{
DWORD *dstpixel, val, buf;
DWORD *ptr = (DWORD *)(srcbits + left*3);
BYTE *bits;
int div = dstwidth % 4;
int divk;
for(h = lines - 1; h >= 0; h--)
{
dstpixel = (DWORD *) (bmpImage->data + h*bmpImage->bytes_per_line + left*4);
for (x = 0; x < dstwidth/4; x++) { /* do 3 dwords source, 4 dwords dest at a time */
buf = *ptr++;
*dstpixel++ = buf&0x00ffffff; /* b1, g1, r1 */
val = (buf >> 24); /* b2 */
buf = *ptr++;
*dstpixel++ = (val | (buf<<8)) &0x00ffffff; /* g2, r2 */
val = (buf >> 16); /* b3, g3 */
buf = *ptr++;
*dstpixel++ = (val | (buf<<16)) &0x00ffffff; /* r3 */
*dstpixel++ = (buf >> 8); /* b4, g4, r4 */
}
for ( divk=div, bits=(BYTE*)ptr; divk>0; divk--, bits+=3 ) /* do remainder */
{
*dstpixel++ = *(DWORD*)bits & 0x00ffffff; /* b, g, r */
}
ptr = (DWORD*)((srcbits+=linebytes)+left*3);
}
}
else if( bmpImage->blue_mask == 0xff0000 && bmpImage->red_mask == 0xff ) /* packed BGR to unpacked RGB */
{
DWORD *dstpixel, val, buf;
DWORD *ptr = (DWORD *)(srcbits + left*3);
BYTE *bits;
int div = dstwidth % 4;
int divk;
for(h = lines - 1; h >= 0; h--)
{
dstpixel = (DWORD *) (bmpImage->data + h*bmpImage->bytes_per_line + left*4);
for (x = 0; x < dstwidth/4; x++) { /* do 3 dwords source, 4 dwords dest at a time */
buf = *ptr++;
*dstpixel++ = ((buf&0xff)<<16) | (buf&0xff00) | ((buf&0xff0000)>>16); /* b1, g1, r1 */
val = ((buf&0xff000000)>>8); /* b2 */
buf = *ptr++;
*dstpixel++ = val | ((buf&0xff)<<8) | ((buf&0xff00)>>8); /* g2, r2 */
val = (buf&0xff0000) | ((buf&0xff000000)>>16); /* b3, g3 */
buf = *ptr++;
*dstpixel++ = val | (buf&0xff); /* r3 */
*dstpixel++ = ((buf&0xff00)<<8) | ((buf&0xff0000)>>8) | (buf>>24); /* b4, g4, r4 */
}
for ( divk=div, bits=(BYTE*)ptr; divk>0; divk--, bits+=3 ) /* do remainder */
{
buf = *(DWORD*)bits;
*dstpixel++ = ((buf&0xff)<<16) | (buf&0xff00) | ((buf&0xff0000)>>16); /* b, g, r */
}
ptr = (DWORD*)((srcbits+=linebytes)+left*3);
}
}
else
goto notsupported;
}
break;
case 15:
{
if( bmpImage->blue_mask == 0x7c00 && bmpImage->red_mask == 0x1f ) /* BGR888 to RGB555 */
{
DWORD *ptr = (DWORD *)(srcbits + left*3);
LPBYTE bits;
LPWORD dstpixel;
int div = dstwidth % 4;
int divk;
for (h = lines - 1; h >= 0; h--) { /* Do 4 pixels at a time */
dstpixel = (LPWORD) (bmpImage->data + h * bmpImage->bytes_per_line + left*2);
for (x = 0; x < dstwidth/4; x++, ptr += 3) {
*dstpixel++ = ((ptr[0] << 7) & 0x7c00) | ((ptr[0] >> 6) & 0x03e0) | ((ptr[0] >> 19) & 0x1f);
*dstpixel++ = ((ptr[0] >> 17) & 0x7c00) | ((ptr[1] << 2) & 0x03e0) | ((ptr[1] >> 11) & 0x1f);
*dstpixel++ = ((ptr[1] >> 9) & 0x07c00) | ((ptr[1] >> 22) & 0x03e0) | ((ptr[2] >> 3) & 0x1f);
*dstpixel++ = ((ptr[2] >> 1) & 0x07c00) | ((ptr[2] >> 14) & 0x03e0) | ((ptr[2] >> 27) & 0x1f);
}
for (bits = (LPBYTE)ptr, divk=div; divk > 0; divk--, bits+=3) /* dstwidth not divisible by 4? */
*dstpixel++ = (((WORD)bits[0] << 7) & 0x07c00) |
(((WORD)bits[1] << 2) & 0x03e0) |
(((WORD)bits[2] >> 3) & 0x001f);
ptr = (DWORD *)((srcbits += linebytes) + left * 3);
}
}
else if( bmpImage->blue_mask == 0x1f && bmpImage->red_mask == 0x7c00 ) /* BGR888 to BGR555 */
{
DWORD *ptr = (DWORD *)(srcbits + left*3);
LPBYTE bits;
LPWORD dstpixel;
int div = dstwidth % 4;
int divk;
for (h = lines - 1; h >= 0; h--) { /* Do 4 pixels at a time */
dstpixel = (LPWORD) (bmpImage->data + h * bmpImage->bytes_per_line + left*2);
for (x = 0; x < dstwidth/4; x++, ptr += 3) {
*dstpixel++ = ((ptr[0] >> 3) & 0x1f) | ((ptr[0] >> 6) & 0x03e0) | ((ptr[0] >> 9) & 0x7c00);
*dstpixel++ = ((ptr[0] >> 27) & 0x1f) | ((ptr[1] << 2) & 0x03e0) | ((ptr[1] >> 1) & 0x7c00);
*dstpixel++ = ((ptr[1] >> 19) & 0x1f) | ((ptr[1] >> 22) & 0x03e0) | ((ptr[2] << 7) & 0x7c00);
*dstpixel++ = ((ptr[2] >> 11) & 0x1f) | ((ptr[2] >> 14) & 0x03e0) | ((ptr[2] >> 17) & 0x7c00);
}
for (bits = (LPBYTE)ptr, divk=div; divk > 0; divk--, bits+=3) /* dstwidth not divisible by 4? */
*dstpixel++ = (((WORD)bits[2] << 7) & 0x07c00) |
(((WORD)bits[1] << 2) & 0x03e0) |
(((WORD)bits[0] >> 3) & 0x001f);
ptr = (DWORD *)((srcbits += linebytes) + left * 3);
}
}
else
goto notsupported;
}
break;
case 16:
{
DWORD *ptr = (DWORD *)(srcbits + left*3);
LPBYTE bits;
LPWORD dstpixel;
int div = dstwidth % 4;
int divk;
if( bmpImage->blue_mask == 0x001f && bmpImage->red_mask == 0xf800 ) /* BGR888 to BGR565 */
{
for (h = lines - 1; h >= 0; h--) { /* Do 4 pixels at a time */
dstpixel = (LPWORD) (bmpImage->data + h * bmpImage->bytes_per_line + left*2);
for (x = 0; x < dstwidth/4; x++, ptr += 3) {
*dstpixel++ = ((ptr[0] >> 3) & 0x1f) | ((ptr[0] >> 5) & 0x07e0) | ((ptr[0] >> 8) & 0xf800);
*dstpixel++ = ((ptr[0] >> 27) & 0x1f) | ((ptr[1] << 3) & 0x07e0) | (ptr[1] & 0xf800);
*dstpixel++ = ((ptr[1] >> 19) & 0x1f) | ((ptr[1] >> 21) & 0x07e0) | ((ptr[2] << 8) & 0xf800);
*dstpixel++ = ((ptr[2] >> 11) & 0x1f) | ((ptr[2] >> 13) & 0x07e0) | ((ptr[2] >> 16) & 0xf800);
}
for ( bits = (LPBYTE)ptr, divk=div; divk > 0; divk--, bits+=3) /* dstwidth is not divisible by 4? */
*dstpixel++ = (((WORD)bits[2] << 8) & 0xf800) |
(((WORD)bits[1] << 3) & 0x07e0) |
(((WORD)bits[0] >> 3) & 0x001f);
ptr = (DWORD *)((srcbits += linebytes) + left * 3);
}
}
else if( bmpImage->blue_mask == 0xf800 && bmpImage->red_mask == 0x001f ) /* BGR888 to RGB565 */
{
for (h = lines - 1; h >= 0; h--) { /* Do 4 pixels at a time */
dstpixel = (LPWORD) (bmpImage->data + h * bmpImage->bytes_per_line + left*2);
for (x = 0; x < dstwidth/4; x++, ptr += 3) {
*dstpixel++ = ((ptr[0] << 8) & 0xf800) | ((ptr[0] >> 5) & 0x07e0) | ((ptr[0] >> 19) & 0x1f);
*dstpixel++ = ((ptr[0] >> 16) & 0xf800) | ((ptr[1] << 3) & 0x07e0) | ((ptr[1] >> 11) & 0x1f);
*dstpixel++ = ((ptr[1] >> 8) & 0xf800) | ((ptr[1] >> 21) & 0x07e0) | ((ptr[2] >> 3) & 0x1f);
*dstpixel++ = (ptr[2] & 0xf800) | ((ptr[2] >> 13) & 0x07e0) | ((ptr[2] >> 27) & 0x1f);
}
for ( bits = (LPBYTE)ptr, divk=div; divk > 0; divk--, bits+=3) /* dstwidth is not divisible by 4? */
*dstpixel++ = (((WORD)bits[0] << 8) & 0xf800) |
(((WORD)bits[1] << 3) & 0x07e0) |
(((WORD)bits[2] >> 3) & 0x001f);
ptr = (DWORD *)((srcbits += linebytes) + left * 3);
}
}
else
goto notsupported;
}
break;
case 1:
case 4:
case 8:
{
LPBYTE bits = (LPBYTE)srcbits + left*3;
for (h = lines - 1; h >= 0; h--) {
for (x = left; x < dstwidth+left; x++, bits+=3)
XPutPixel( bmpImage, x, h,
X11DRV_PALETTE_ToPhysical(dc, RGB(bits[2], bits[1], bits[0])));
bits = (LPBYTE)(srcbits += linebytes) + left * 3;
}
}
break;
default:
notsupported:
FIXME("from 24 bit DIB to %d bit bitmap with mask R,G,B %x,%x,%x\n",
bmpImage->bits_per_pixel, (int)bmpImage->red_mask,
(int)bmpImage->green_mask, (int)bmpImage->blue_mask );
break;
}
}
/***********************************************************************
* X11DRV_DIB_GetImageBits_24
*
* GetDIBits for an 24-bit deep DIB.
*/
static void X11DRV_DIB_GetImageBits_24( int lines, BYTE *dstbits,
DWORD dstwidth, DWORD srcwidth,
PALETTEENTRY *srccolors,
XImage *bmpImage, DWORD linebytes )
{
DWORD x, val;
int h;
if (lines < 0 )
{
lines = -lines;
dstbits = dstbits + ( linebytes * (lines-1) );
linebytes = -linebytes;
}
switch ( bmpImage->depth )
{
case 24:
{
if (bmpImage->bits_per_pixel == 24) {
int tocopy = linebytes;
BYTE *srcpixel;
BYTE *ptr = (LPBYTE)dstbits;
if (tocopy < 0 ) tocopy = -tocopy;
srcpixel = bmpImage->data + lines*tocopy;
for(h = lines ; h-- ; ) {
srcpixel-=tocopy;
memcpy(ptr,srcpixel,tocopy);
ptr = (LPBYTE)(dstbits+=linebytes);
}
break;
}
}
case 32:
{
DWORD *srcpixel, buf;
LPBYTE bits;
DWORD *ptr=(DWORD *)dstbits;
int quotient = dstwidth / 4;
int remainder = dstwidth % 4;
int remk;
/* ==== 24/32 BGR bitmap to 24 BGR dib==== */
if( bmpImage->blue_mask == 0xff && bmpImage->red_mask == 0xff0000 )
{
for(h = lines - 1; h >= 0; h--)
{
srcpixel = (DWORD *) (bmpImage->data + h * bmpImage->bytes_per_line);
for (x = 0; x < quotient; x++) { /* do 4 dwords source, 3 dwords dest at a time */
buf = ((*srcpixel++)&0x00ffffff); /* b1, g1, r1*/
*ptr++ = buf | ((*srcpixel)<<24); /* b2 */
buf = ((*srcpixel++>>8)&0x0000ffff); /* g2, r2 */
*ptr++ = buf | ((*srcpixel)<<16); /* b3, g3 */
buf = ((*srcpixel++>>16)&0x000000ff); /* r3 */
*ptr++ = buf | ((*srcpixel++)<<8); /* b4, g4, r4 */
}
for ( remk=remainder, bits=(BYTE*)ptr; remk>0; remk--, bits+=3 ) /* do remainder */
{
buf=*srcpixel++;
*(WORD*)bits = buf; /* b, g */
*(bits+2) = buf>>16; /* r */
}
ptr = (DWORD*)(dstbits+=linebytes);
}
}
/* ==== 24/32 RGB bitmap to 24 BGR dib ==== */
else if( bmpImage->blue_mask == 0xff0000 && bmpImage->red_mask == 0xff )
{
for(h = lines - 1; h >= 0; h--)
{
srcpixel = (DWORD *) (bmpImage->data + h * bmpImage->bytes_per_line);
for (x = 0; x < quotient; x++) { /* do 4 dwords source, 3 dwords dest at a time */
buf = *srcpixel++;
val = ((buf&0xff0000)>>16) | (buf&0xff00) | ((buf&0xff)<<16); /* b1, g1, r1 */
buf = *srcpixel++;
*ptr++ = val | ((buf&0xff0000)<<8); /* b2 */
val = ((buf&0xff00)>>8) | ((buf&0xff)<<8); /* g2, r2 */
buf = *srcpixel++;
*ptr++ = val | (buf&0xff0000) | ((buf&0xff00)<<16); /* b3, g3 */
val = (buf&0xff); /* r3 */
buf = *srcpixel++;
*ptr++ = val | ((buf&0xff0000)>>8) | ((buf&0xff00)<<8) | (buf<<24); /* b4, g4, r4 */
}
for ( remk=remainder, bits=(BYTE*)ptr; remk>0; remk--, bits+=3 ) /* do remainder */
{
buf=*srcpixel++;
*(WORD*)bits = (buf&0xff00) | ((buf&0xff0000)>>16) ; /* b, g */
*(bits+2) = buf; /* r */
}
ptr = (DWORD*)(dstbits+=linebytes);
}
}
else goto notsupported;
}
break;
case 15:
{
LPWORD srcpixel;
LPBYTE bits = dstbits;
WORD val;
/* ==== 555 BGR bitmap to 24 BGR dib ==== */
if( bmpImage->blue_mask == 0x1f && bmpImage->red_mask == 0x7c00 )
{
for (h = lines - 1; h >= 0; h--) {
srcpixel = (LPWORD) (bmpImage->data + h * bmpImage->bytes_per_line);
for (x = 0; x < srcwidth; x++, bits += 3) {
val = *srcpixel++;
bits[2] = (BYTE)(((val >> 7) & 0xf8) | ((val >> 12) & 0x07)); /*Red*/
bits[1] = (BYTE)(((val >> 2) & 0xf8) | ((val >> 7) & 0x07)); /*Green*/
bits[0] = (BYTE)(((val << 3) & 0xf8) | ((val >> 2) & 0x07)); /*Blue*/
}
bits = (dstbits += linebytes);
}
}
/* ==== 555 RGB bitmap to 24 RGB dib==== */
else if( bmpImage->blue_mask == 0x7c00 && bmpImage->red_mask == 0x1f )
{
for (h = lines - 1; h >= 0; h--) {
srcpixel = (LPWORD) (bmpImage->data + h * bmpImage->bytes_per_line);
for (x = 0; x < srcwidth; x++, bits += 3) {
val = *srcpixel++;
bits[0] = (BYTE)(((val >> 7) & 0xf8) | ((val >> 12) & 0x07)); /*Red*/
bits[1] = (BYTE)(((val >> 2) & 0xf8) | ((val >> 7) & 0x07)); /*Green*/
bits[2] = (BYTE)(((val << 3) & 0xf8) | ((val >> 2) & 0x07)); /*Blue*/
}
bits = (dstbits += linebytes);
}
}
else goto notsupported;
}
break;
case 16:
{
LPWORD srcpixel;
LPBYTE bits = dstbits;
WORD val;
/* ==== 565 BGR bitmap to 24 BGR dib ==== */
if( bmpImage->blue_mask == 0x1f && bmpImage->red_mask == 0xf800 )
{
for (h = lines - 1; h >= 0; h--) {
srcpixel = (LPWORD) (bmpImage->data + h * bmpImage->bytes_per_line);
for (x = 0; x < srcwidth; x++, bits += 3) {
val = *srcpixel++;
bits[2] = (BYTE)(((val >> 8) & 0xf8) | ((val >> 13) & 0x07)); /*Red*/
bits[1] = (BYTE)(((val >> 3) & 0xfc) | ((val >> 9) & 0x03)); /*Green*/
bits[0] = (BYTE)(((val << 3) & 0xf8) | ((val >> 2) & 0x07)); /*Blue*/
}
bits = (dstbits += linebytes);
}
}
/* ==== 565 RGB bitmap to 24 BGR dib ==== */
else if( bmpImage->blue_mask == 0xf800 && bmpImage->red_mask == 0x1f )
{
for (h = lines - 1; h >= 0; h--) {
srcpixel = (LPWORD) (bmpImage->data + h * bmpImage->bytes_per_line);
for (x = 0; x < srcwidth; x++, bits += 3) {
val = *srcpixel++;
bits[0] = (BYTE)(((val >> 8) & 0xf8) | ((val >> 13) & 0x07)); /*Red*/
bits[1] = (BYTE)(((val >> 3) & 0xfc) | ((val >> 9) & 0x03)); /*Green*/
bits[2] = (BYTE)(((val << 3) & 0xf8) | ((val >> 2) & 0x07)); /*Blue*/
}
bits = (dstbits += linebytes);
}
}
else goto notsupported;
}
break;
case 1:
/* ==== monochrome bitmap to 24 BGR dib ==== */
case 4:
/* ==== 4 colormap bitmap to 24 BGR dib ==== */
if (bmpImage->red_mask==0 && bmpImage->green_mask==0 && bmpImage->blue_mask==0 && srccolors)
{
LPBYTE bits = dstbits;
PALETTEENTRY val;
for (h = lines - 1; h >= 0; h--) {
for (x = 0; x < dstwidth; x++) {
val = srccolors[XGetPixel(bmpImage, x, h)];
*bits++ = val.peBlue;
*bits++ = val.peGreen;
*bits++ = val.peRed;
}
bits = (dstbits += linebytes);
}
}
else goto notsupported;
break;
case 8:
/* ==== 8 colormap bitmap to 24 BGR dib ==== */
if (bmpImage->red_mask==0 && bmpImage->green_mask==0 && bmpImage->blue_mask == 0 && srccolors)
{
BYTE *srcpixel;
LPBYTE bits = dstbits;
PALETTEENTRY val;
for (h = lines - 1; h >= 0; h--) {
srcpixel = bmpImage->data + h*bmpImage->bytes_per_line;
for (x = 0; x < dstwidth; x++ ) {
val = srccolors[(int)*srcpixel++];
*bits++ = val.peBlue; /*Blue*/
*bits++ = val.peGreen; /*Green*/
*bits++ = val.peRed; /*Red*/
}
bits = (dstbits += linebytes);
}
}
else goto notsupported;
break;
default:
notsupported:
{
LPBYTE bits = dstbits;
FIXME("from %d bit bitmap with mask R,G,B %x,%x,%x to 24 bit DIB\n",
bmpImage->depth, (int)bmpImage->red_mask,
(int)bmpImage->green_mask, (int)bmpImage->blue_mask );
for (h = lines - 1; h >= 0; h--)
{
for (x = 0; x < dstwidth; x++, bits += 3)
{
COLORREF pixel = X11DRV_PALETTE_ToLogical( XGetPixel( bmpImage, x, h ) );
bits[0] = GetBValue(pixel);
bits[1] = GetGValue(pixel);
bits[2] = GetRValue(pixel);
}
bits = (dstbits += linebytes);
}
}
break;
}
}
/***********************************************************************
* X11DRV_DIB_SetImageBits_32
*
* SetDIBits for a 32-bit deep DIB.
*/
static void X11DRV_DIB_SetImageBits_32( int lines, const BYTE *srcbits,
DWORD srcwidth, DWORD dstwidth, int left,
DC *dc, XImage *bmpImage,
DWORD linebytes )
{
DWORD x, *ptr;
int h;
if (lines < 0 )
{
lines = -lines;
srcbits = srcbits + ( linebytes * (lines-1) );
linebytes = -linebytes;
}
ptr = (DWORD *) srcbits + left;
switch ( bmpImage->depth )
{
case 32:
/* ==== 32 BGR dib to 24/32 BGR bitmap ==== */
if (bmpImage->red_mask == 0xff0000 && bmpImage->blue_mask == 0xff) {
for (h = lines - 1; h >= 0; h--, srcbits+=linebytes) {
memcpy( bmpImage->data + h * bmpImage->bytes_per_line, srcbits + left*4, dstwidth*4 );
}
}
/* ==== 32 BGR dib to 24/32 RGB bitmap ==== */
else if (bmpImage->red_mask == 0xff && bmpImage->blue_mask == 0xff0000)
{
DWORD *dstpixel;
for (h = lines - 1; h >= 0; h--) {
dstpixel = (DWORD *) (bmpImage->data + h * bmpImage->bytes_per_line);
for (x = 0; x < dstwidth; x++, ptr++) {
*dstpixel++ = ((*ptr << 16) & 0xff0000) | (*ptr & 0xff00) | ((*ptr >> 16) & 0xff);
}
ptr = (DWORD *) (srcbits += linebytes) + left;
}
}
else goto notsupported;
break;
case 24:
/* ==== 32 BGR dib to 24 (888) BGR bitmap ==== */
/* we need to check that source mask matches destination */
if (bmpImage->bits_per_pixel == 32)
{
for (h = lines - 1; h >= 0; h--, srcbits+=linebytes) {
memcpy( bmpImage->data + h * bmpImage->bytes_per_line, srcbits + left*4, dstwidth*4 );
}
}
else
{
BYTE *bptr;
ptr = (DWORD *) srcbits + left;
bptr = bmpImage->data;
for (h = lines - 1; h >= 0; h--) {
for (x = 0; x < dstwidth; x++) {
/* *ptr is a 32bit value */
/* bptr points to first of 3 bytes */
*bptr++ = (*ptr >> 16) & 0xff;
*bptr++ = (*ptr >> 8) & 0xff;
*bptr++ = (*ptr ) & 0xff;
ptr++;
}
ptr = (DWORD *) (srcbits += linebytes) + left;
}
}
break;
case 15:
/* ==== 32 BGR dib to 555 BGR bitmap ==== */
if (bmpImage->red_mask == 0x7c00 && bmpImage->blue_mask == 0x001f) {
LPWORD dstpixel;
for (h = lines - 1; h >= 0; h--) {
dstpixel = (LPWORD) (bmpImage->data + h * bmpImage->bytes_per_line);
for (x = 0; x < dstwidth; x++, ptr++) {
*dstpixel++ = (WORD) (((*ptr >> 9) & 0x7c00) | ((*ptr >> 6) & 0x03e0) | ((*ptr >> 3) & 0x001f));
}
ptr = (DWORD *) (srcbits += linebytes) + left;
}
}
/* ==== 32 BGR dib to 555 RGB bitmap ==== */
else if (bmpImage->red_mask == 0x001f && bmpImage->blue_mask == 0x7c00)
{
LPWORD dstpixel;
for (h = lines - 1; h >= 0; h--) {
dstpixel = (LPWORD) (bmpImage->data + h * bmpImage->bytes_per_line);
for (x = 0; x < dstwidth; x++, ptr++) {
*dstpixel++ = (WORD) (((*ptr << 7) & 0x7c00) | ((*ptr >> 6) & 0x03e0) | ((*ptr >> 19) & 0x001f));
}
ptr = (DWORD *) (srcbits += linebytes) + left;
}
}
else goto notsupported;
break;
case 16:
/* ==== 32 BGR dib to 565 BGR bitmap ==== */
if (bmpImage->red_mask == 0xf800 && bmpImage->blue_mask == 0x001f)
{
LPWORD dstpixel;
for (h = lines - 1; h >= 0; h--) {
dstpixel = (LPWORD) (bmpImage->data + h * bmpImage->bytes_per_line);
for (x = 0; x < dstwidth; x++, ptr++) {
*dstpixel++ = (WORD) (((*ptr >> 8) & 0xf800) | ((*ptr >> 5) & 0x07e0) | ((*ptr >> 3) & 0x001f));
}
ptr = (DWORD *) (srcbits += linebytes) + left;
}
}
/* ==== 32 BGR dib to 565 RGB bitmap ==== */
else if (bmpImage->red_mask == 0x001f && bmpImage->blue_mask == 0xf800)
{
LPWORD dstpixel;
for (h = lines - 1; h >= 0; h--) {
dstpixel = (LPWORD) (bmpImage->data + h * bmpImage->bytes_per_line);
for (x = 0; x < dstwidth; x++, ptr++) {
*dstpixel++ = (WORD) (((*ptr << 8) & 0xf800) | ((*ptr >> 5) & 0x07e0) | ((*ptr >> 19) & 0x001f));
}
ptr = (DWORD *) (srcbits += linebytes) + left;
}
}
else goto notsupported;
break;
case 1:
case 4:
case 8:
{
LPBYTE bits = (LPBYTE)srcbits + left*4;
for (h = lines - 1; h >= 0; h--) {
for (x = left; x < dstwidth+left; x++, bits += 4)
XPutPixel( bmpImage, x, h,
X11DRV_PALETTE_ToPhysical(dc, RGB( bits[2], bits[1], *bits )));
bits = (LPBYTE)(srcbits += linebytes) + left * 4;
}
}
break;
default:
notsupported:
FIXME("32 bit DIB %d bit bitmap\n", bmpImage->bits_per_pixel);
break;
}
}
/***********************************************************************
* X11DRV_DIB_GetImageBits_32
*
* GetDIBits for an 32-bit deep DIB.
*/
static void X11DRV_DIB_GetImageBits_32( int lines, BYTE *dstbits,
DWORD dstwidth, DWORD srcwidth,
PALETTEENTRY *srccolors,
XImage *bmpImage, DWORD linebytes )
{
DWORD x;
int h;
BYTE *bits;
DWORD copybytes = srcwidth * 4;
if (lines < 0 )
{
lines = -lines;
dstbits = dstbits + ( linebytes * (lines-1) );
linebytes = -linebytes;
}
bits = dstbits;
switch ( bmpImage->depth )
{
case 32:
/* ==== 24/32 BGR bitmap to 32 BGR dib ==== */
if ( bmpImage->red_mask == 0xff0000 && bmpImage->blue_mask == 0xff )
for (h = lines - 1; h >= 0; h--, dstbits+=linebytes)
memcpy( dstbits, bmpImage->data + h*bmpImage->bytes_per_line, copybytes );
/* ==== 24/32 RGB bitmap to 32 BGR dib ==== */
else if ( bmpImage->red_mask == 0xff && bmpImage->blue_mask == 0xff0000 )
{
LPBYTE srcbits;
for (h = lines - 1; h >= 0; h--) {
srcbits = bmpImage->data + h * bmpImage->bytes_per_line;
for (x = 0; x < dstwidth; x++, bits+=4, srcbits+=2) {
*(bits + 2) = *srcbits++;
*(bits + 1) = *srcbits++;
*bits = *srcbits;
}
bits = (dstbits += linebytes);
}
}
else goto notsupported;
break;
case 24:
/* ==== 24 BGR bitmap to 32 (0888) BGR dib ==== */
/* we need to check that source mask matches destination */
{
DWORD *srcpixel;
BYTE *bptr;
DWORD srcdata;
srcpixel = (DWORD *) dstbits;
bptr = bmpImage->data;
for (h = lines - 1; h >= 0; h--) {
for (x = 0; x < dstwidth; x++) {
/* *srcpixel is a 32bit value */
/* bptr points to first of 3 bytes */
srcdata = 0;
srcdata = srcdata << 8 | *bptr++;
srcdata = srcdata << 8 | *bptr++;
srcdata = srcdata << 8 | *bptr++;
*srcpixel++ = srcdata;
}
srcpixel = (DWORD *) (dstbits += linebytes);
}
}
break;
case 15:
{
LPWORD srcpixel;
WORD val;
/* ==== 555 BGR bitmap to 32 BGR dib ==== */
if (bmpImage->red_mask == 0x7c00 && bmpImage->blue_mask == 0x001f)
{
for (h = lines - 1; h >= 0; h--) {
srcpixel = (LPWORD) (bmpImage->data + h * bmpImage->bytes_per_line);
for (x = 0; x < dstwidth; x++, bits+=2) {
val = *srcpixel++;
*bits++ = (BYTE)(((val << 3) & 0xf8) | ((val >> 2) & 0x03)); /*Blue*/
*bits++ = (BYTE)(((val >> 2) & 0xfc) | ((val >> 8) & 0x03)); /*Green*/
*bits = (BYTE)(((val >> 7) & 0xf8) | ((val >> 12) & 0x07)); /*Red*/
}
bits = (dstbits += linebytes);
}
}
/* ==== 555 RGB bitmap to 32 BGR dib ==== */
else if (bmpImage->red_mask == 0x001f && bmpImage->blue_mask == 0x7c00)
{
for (h = lines - 1; h >= 0; h--) {
srcpixel = (LPWORD) (bmpImage->data + h * bmpImage->bytes_per_line);
for (x = 0; x < dstwidth; x++, bits+=2) {
val = *srcpixel++;
*bits++ = (BYTE)(((val >> 7) & 0xf8) | ((val >> 12) & 0x07));/*Blue*/
*bits++ = (BYTE)(((val >> 2) & 0xfc) | ((val >> 8) & 0x03)); /*Green*/
*bits = (BYTE)(((val << 3) & 0xf8) | ((val >> 2) & 0x03)); /*Red*/
}
bits = (dstbits += linebytes);
}
}
else goto notsupported;
}
break;
case 16:
{
LPWORD srcpixel;
WORD val;
/* ==== 565 BGR bitmap to 32 BGR dib ==== */
if (bmpImage->red_mask == 0xf800 && bmpImage->blue_mask == 0x001f)
{
for (h = lines - 1; h >= 0; h--) {
srcpixel = (LPWORD) (bmpImage->data + h * bmpImage->bytes_per_line);
for (x = 0; x < srcwidth; x++, bits+=2) {
val = *srcpixel++;
*bits++ = (BYTE)(((val << 3) & 0xf8) | ((val >> 2) & 0x03)); /*Blue*/
*bits++ = (BYTE)(((val >> 3) & 0xfc) | ((val >> 9) & 0x03)); /*Green*/
*bits = (BYTE)(((val >> 8) & 0xf8) | ((val >> 13) & 0x07)); /*Red*/
}
bits = (dstbits += linebytes);
}
}
/* ==== 565 RGB bitmap to 32 BGR dib ==== */
else if (bmpImage->red_mask == 0xf800 && bmpImage->blue_mask == 0x001f)
{
for (h = lines - 1; h >= 0; h--) {
srcpixel = (LPWORD) (bmpImage->data + h * bmpImage->bytes_per_line);
for (x = 0; x < srcwidth; x++, bits+=2) {
val = *srcpixel++;
*bits++ = (BYTE)(((val >> 8) & 0xf8) | ((val >> 13) & 0x07));/*Blue*/
*bits++ = (BYTE)(((val >> 3) & 0xfc) | ((val >> 9) & 0x03)); /*Green*/
*bits = (BYTE)(((val << 3) & 0xf8) | ((val >> 2) & 0x03)); /*Red*/
}
bits = (dstbits += linebytes);
}
}
else goto notsupported;
}
break;
case 1:
/* ==== monochrome bitmap to 32 BGR dib ==== */
case 4:
/* ==== 4 colormap bitmap to 32 BGR dib ==== */
if (bmpImage->red_mask==0 && bmpImage->green_mask==0 && bmpImage->blue_mask==0 && srccolors)
{
PALETTEENTRY val;
for (h = lines - 1; h >= 0; h--) {
for (x = 0; x < dstwidth; x++) {
val = srccolors[XGetPixel(bmpImage, x, h)];
*bits++ = val.peBlue;
*bits++ = val.peGreen;
*bits++ = val.peRed;
*bits++ = 0;
}
bits = (dstbits += linebytes);
}
}
else goto notsupported;
break;
case 8:
/* ==== 8 colormap bitmap to 32 BGR dib ==== */
if (bmpImage->red_mask==0 && bmpImage->green_mask==0 && bmpImage->blue_mask==0 && srccolors)
{
BYTE *srcpixel;
PALETTEENTRY val;
for (h = lines - 1; h >= 0; h--) {
srcpixel = bmpImage->data + h*bmpImage->bytes_per_line;
for (x = 0; x < dstwidth; x++) {
val = srccolors[(int)*srcpixel++];
*bits++ = val.peBlue; /*Blue*/
*bits++ = val.peGreen; /*Green*/
*bits++ = val.peRed; /*Red*/
*bits++ = 0;
}
bits = (dstbits += linebytes);
}
}
else goto notsupported;
break;
default:
notsupported:
FIXME("from %d bit bitmap with mask R,G,B %x,%x,%x to 32 bit DIB\n",
bmpImage->depth, (int)bmpImage->red_mask,
(int)bmpImage->green_mask, (int)bmpImage->blue_mask );
for (h = lines - 1; h >= 0; h--)
{
for (x = 0; x < dstwidth; x++, bits += 4)
{
COLORREF pixel = X11DRV_PALETTE_ToLogical( XGetPixel( bmpImage, x, h ) );
bits[0] = GetBValue(pixel);
bits[1] = GetGValue(pixel);
bits[2] = GetRValue(pixel);
}
bits = (dstbits += linebytes);
}
break;
}
}
/***********************************************************************
* X11DRV_DIB_SetImageBits
*
* Transfer the bits to an X image.
* Helper function for SetDIBits() and SetDIBitsToDevice().
*/
static int X11DRV_DIB_SetImageBits( const X11DRV_DIB_IMAGEBITS_DESCR *descr )
{
int lines = descr->lines >= 0 ? descr->lines : -descr->lines;
XImage *bmpImage;
wine_tsx11_lock();
if (descr->image)
bmpImage = descr->image;
else {
bmpImage = XCreateImage( gdi_display, visual, descr->depth, ZPixmap, 0, NULL,
descr->infoWidth, lines, 32, 0 );
bmpImage->data = calloc( lines, bmpImage->bytes_per_line );
if(bmpImage->data == NULL) {
ERR("Out of memory!\n");
XDestroyImage( bmpImage );
wine_tsx11_unlock();
return lines;
}
}
/* Transfer the pixels */
switch(descr->infoBpp)
{
case 1:
X11DRV_DIB_SetImageBits_1( descr->lines, descr->bits, descr->infoWidth,
descr->width, descr->xSrc, (int *)(descr->colorMap),
bmpImage, descr->dibpitch );
break;
case 4:
if (descr->compression) {
XGetSubImage( gdi_display, descr->drawable, descr->xDest, descr->yDest,
descr->width, descr->height, AllPlanes, ZPixmap,
bmpImage, descr->xSrc, descr->ySrc );
X11DRV_DIB_SetImageBits_RLE4( descr->lines, descr->bits,
descr->infoWidth, descr->width,
descr->xSrc, (int *)(descr->colorMap),
bmpImage );
} else
X11DRV_DIB_SetImageBits_4( descr->lines, descr->bits,
descr->infoWidth, descr->width,
descr->xSrc, (int*)(descr->colorMap),
bmpImage, descr->dibpitch );
break;
case 8:
if (descr->compression) {
XGetSubImage( gdi_display, descr->drawable, descr->xDest, descr->yDest,
descr->width, descr->height, AllPlanes, ZPixmap,
bmpImage, descr->xSrc, descr->ySrc );
X11DRV_DIB_SetImageBits_RLE8( descr->lines, descr->bits,
descr->infoWidth, descr->width,
descr->xSrc, (int *)(descr->colorMap),
bmpImage );
} else
X11DRV_DIB_SetImageBits_8( descr->lines, descr->bits,
descr->infoWidth, descr->width,
descr->xSrc, (int *)(descr->colorMap),
bmpImage, descr->dibpitch );
break;
case 15:
case 16:
X11DRV_DIB_SetImageBits_16( descr->lines, descr->bits,
descr->infoWidth, descr->width,
descr->xSrc, descr->dc,
descr->rMask, descr->gMask, descr->bMask,
bmpImage, descr->dibpitch);
break;
case 24:
X11DRV_DIB_SetImageBits_24( descr->lines, descr->bits,
descr->infoWidth, descr->width,
descr->xSrc, descr->dc, bmpImage,
descr->dibpitch);
break;
case 32:
X11DRV_DIB_SetImageBits_32( descr->lines, descr->bits,
descr->infoWidth, descr->width,
descr->xSrc, descr->dc,
bmpImage, descr->dibpitch);
break;
default:
WARN("(%d): Invalid depth\n", descr->infoBpp );
break;
}
TRACE("XPutImage(%ld,%p,%p,%d,%d,%d,%d,%d,%d)\n",
descr->drawable, descr->gc, bmpImage,
descr->xSrc, descr->ySrc, descr->xDest, descr->yDest,
descr->width, descr->height);
#ifdef HAVE_LIBXXSHM
if (descr->useShm)
{
XShmPutImage( gdi_display, descr->drawable, descr->gc, bmpImage,
descr->xSrc, descr->ySrc, descr->xDest, descr->yDest,
descr->width, descr->height, FALSE );
XSync( gdi_display, 0 );
}
else
#endif
XPutImage( gdi_display, descr->drawable, descr->gc, bmpImage,
descr->xSrc, descr->ySrc, descr->xDest, descr->yDest,
descr->width, descr->height );
if (!descr->image) XDestroyImage( bmpImage );
wine_tsx11_unlock();
return lines;
}
/***********************************************************************
* X11DRV_DIB_GetImageBits
*
* Transfer the bits from an X image.
*/
static int X11DRV_DIB_GetImageBits( const X11DRV_DIB_IMAGEBITS_DESCR *descr )
{
int lines = descr->lines >= 0 ? descr->lines : -descr->lines;
XImage *bmpImage;
wine_tsx11_lock();
if (descr->image)
bmpImage = descr->image;
else {
bmpImage = XCreateImage( gdi_display, visual, descr->depth, ZPixmap, 0, NULL,
descr->infoWidth, lines, 32, 0 );
bmpImage->data = calloc( lines, bmpImage->bytes_per_line );
if(bmpImage->data == NULL) {
ERR("Out of memory!\n");
XDestroyImage( bmpImage );
wine_tsx11_unlock();
return lines;
}
}
TRACE("XGetSubImage(%ld,%d,%d,%d,%d,%ld,%d,%p,%d,%d)\n",
descr->drawable, descr->xSrc, descr->ySrc, descr->width,
lines, AllPlanes, ZPixmap, bmpImage, descr->xDest, descr->yDest);
XGetSubImage( gdi_display, descr->drawable, descr->xSrc, descr->ySrc,
descr->width, lines, AllPlanes, ZPixmap,
bmpImage, descr->xDest, descr->yDest );
/* Transfer the pixels */
switch(descr->infoBpp)
{
case 1:
X11DRV_DIB_GetImageBits_1( descr->lines,(LPVOID)descr->bits,
descr->infoWidth, descr->width,
descr->colorMap, descr->palentry,
bmpImage, descr->dibpitch );
break;
case 4:
if (descr->compression)
FIXME("Compression not yet supported!\n");
else
X11DRV_DIB_GetImageBits_4( descr->lines,(LPVOID)descr->bits,
descr->infoWidth, descr->width,
descr->colorMap, descr->palentry,
bmpImage, descr->dibpitch );
break;
case 8:
if (descr->compression)
FIXME("Compression not yet supported!\n");
else
X11DRV_DIB_GetImageBits_8( descr->lines, (LPVOID)descr->bits,
descr->infoWidth, descr->width,
descr->colorMap, descr->palentry,
bmpImage, descr->dibpitch );
break;
case 15:
case 16:
X11DRV_DIB_GetImageBits_16( descr->lines, (LPVOID)descr->bits,
descr->infoWidth,descr->width,
descr->palentry,
descr->rMask, descr->gMask, descr->bMask,
bmpImage, descr->dibpitch );
break;
case 24:
X11DRV_DIB_GetImageBits_24( descr->lines, (LPVOID)descr->bits,
descr->infoWidth,descr->width,
descr->palentry, bmpImage, descr->dibpitch);
break;
case 32:
X11DRV_DIB_GetImageBits_32( descr->lines, (LPVOID)descr->bits,
descr->infoWidth, descr->width,
descr->palentry, bmpImage, descr->dibpitch);
break;
default:
WARN("(%d): Invalid depth\n", descr->infoBpp );
break;
}
if (!descr->image) XDestroyImage( bmpImage );
wine_tsx11_unlock();
return lines;
}
/*************************************************************************
* X11DRV_SetDIBitsToDevice
*
*/
INT X11DRV_SetDIBitsToDevice( DC *dc, INT xDest, INT yDest, DWORD cx,
DWORD cy, INT xSrc, INT ySrc,
UINT startscan, UINT lines, LPCVOID bits,
const BITMAPINFO *info, UINT coloruse )
{
X11DRV_DIB_IMAGEBITS_DESCR descr;
DWORD width, oldcy = cy;
INT result;
int height, tmpheight;
X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
if (DIB_GetBitmapInfo( &info->bmiHeader, &width, &height,
&descr.infoBpp, &descr.compression ) == -1)
return 0;
tmpheight = height;
if (height < 0) height = -height;
if (!lines || (startscan >= height)) return 0;
if (startscan + lines > height) lines = height - startscan;
if (ySrc < startscan) ySrc = startscan;
else if (ySrc >= startscan + lines) return 0;
if (xSrc >= width) return 0;
if (ySrc + cy >= startscan + lines) cy = startscan + lines - ySrc;
if (xSrc + cx >= width) cx = width - xSrc;
if (!cx || !cy) return 0;
X11DRV_SetupGCForText( dc ); /* To have the correct colors */
TSXSetFunction(gdi_display, physDev->gc, X11DRV_XROPfunction[dc->ROPmode-1]);
switch (descr.infoBpp)
{
case 1:
case 4:
case 8:
descr.colorMap = (RGBQUAD *)X11DRV_DIB_BuildColorMap(
coloruse == DIB_PAL_COLORS ? dc : NULL, coloruse,
dc->bitsPerPixel, info, &descr.nColorMap );
if (!descr.colorMap) return 0;
descr.rMask = descr.gMask = descr.bMask = 0;
break;
case 15:
case 16:
descr.rMask = (descr.compression == BI_BITFIELDS) ? *(DWORD *)info->bmiColors : 0x7c00;
descr.gMask = (descr.compression == BI_BITFIELDS) ? *((DWORD *)info->bmiColors + 1) : 0x03e0;
descr.bMask = (descr.compression == BI_BITFIELDS) ? *((DWORD *)info->bmiColors + 2) : 0x001f;
descr.colorMap = 0;
break;
case 24:
descr.rMask = descr.gMask = descr.bMask = 0;
descr.colorMap = 0;
break;
case 32:
descr.rMask = (descr.compression == BI_BITFIELDS) ? *(DWORD *)info->bmiColors : 0xff0000;
descr.gMask = (descr.compression == BI_BITFIELDS) ? *((DWORD *)info->bmiColors + 1) : 0xff00;
descr.bMask = (descr.compression == BI_BITFIELDS) ? *((DWORD *)info->bmiColors + 2) : 0xff;
descr.colorMap = 0;
break;
}
descr.dc = dc;
descr.bits = bits;
descr.image = NULL;
descr.palentry = NULL;
descr.lines = tmpheight >= 0 ? lines : -lines;
descr.infoWidth = width;
descr.depth = dc->bitsPerPixel;
descr.drawable = physDev->drawable;
descr.gc = physDev->gc;
descr.xSrc = xSrc;
descr.ySrc = tmpheight >= 0 ? lines-(ySrc-startscan)-cy+(oldcy-cy)
: ySrc - startscan;
descr.xDest = dc->DCOrgX + XLPTODP( dc, xDest );
descr.yDest = dc->DCOrgY + YLPTODP( dc, yDest ) +
(tmpheight >= 0 ? oldcy-cy : 0);
descr.width = cx;
descr.height = cy;
descr.useShm = FALSE;
descr.dibpitch = ((width * descr.infoBpp + 31) &~31) / 8;
result = X11DRV_DIB_SetImageBits( &descr );
if (descr.infoBpp <= 8)
HeapFree(GetProcessHeap(), 0, descr.colorMap);
return result;
}
/***********************************************************************
* X11DRV_DIB_SetDIBits
*/
INT X11DRV_DIB_SetDIBits(
BITMAPOBJ *bmp, DC *dc, UINT startscan,
UINT lines, LPCVOID bits, const BITMAPINFO *info,
UINT coloruse, HBITMAP hbitmap)
{
X11DRV_DIB_IMAGEBITS_DESCR descr;
int height, tmpheight;
INT result;
descr.dc = dc;
if (DIB_GetBitmapInfo( &info->bmiHeader, &descr.infoWidth, &height,
&descr.infoBpp, &descr.compression ) == -1)
return 0;
tmpheight = height;
if (height < 0) height = -height;
if (!lines || (startscan >= height))
return 0;
if (startscan + lines > height) lines = height - startscan;
switch (descr.infoBpp)
{
case 1:
case 4:
case 8:
descr.colorMap = (RGBQUAD *)X11DRV_DIB_BuildColorMap(
coloruse == DIB_PAL_COLORS ? descr.dc : NULL, coloruse,
bmp->bitmap.bmBitsPixel,
info, &descr.nColorMap );
if (!descr.colorMap) return 0;
descr.rMask = descr.gMask = descr.bMask = 0;
break;
case 15:
case 16:
descr.rMask = (descr.compression == BI_BITFIELDS) ? *(DWORD *)info->bmiColors : 0x7c00;
descr.gMask = (descr.compression == BI_BITFIELDS) ? *((DWORD *)info->bmiColors + 1) : 0x03e0;
descr.bMask = (descr.compression == BI_BITFIELDS) ? *((DWORD *)info->bmiColors + 2) : 0x001f;
descr.colorMap = 0;
break;
case 24:
descr.rMask = descr.gMask = descr.bMask = 0;
descr.colorMap = 0;
break;
case 32:
descr.rMask = (descr.compression == BI_BITFIELDS) ? *(DWORD *)info->bmiColors : 0xff0000;
descr.gMask = (descr.compression == BI_BITFIELDS) ? *((DWORD *)info->bmiColors + 1) : 0xff00;
descr.bMask = (descr.compression == BI_BITFIELDS) ? *((DWORD *)info->bmiColors + 2) : 0xff;
descr.colorMap = 0;
break;
default: break;
}
/* HACK for now */
if(!bmp->physBitmap)
X11DRV_CreateBitmap(hbitmap);
descr.bits = bits;
descr.image = NULL;
descr.palentry = NULL;
descr.lines = tmpheight >= 0 ? lines : -lines;
descr.depth = bmp->bitmap.bmBitsPixel;
descr.drawable = (Pixmap)bmp->physBitmap;
descr.gc = BITMAP_GC(bmp);
descr.xSrc = 0;
descr.ySrc = 0;
descr.xDest = 0;
descr.yDest = height - startscan - lines;
descr.width = bmp->bitmap.bmWidth;
descr.height = lines;
descr.useShm = FALSE;
descr.dibpitch = ((descr.infoWidth * descr.infoBpp + 31) &~31) / 8;
result = X11DRV_DIB_SetImageBits( &descr );
if (descr.colorMap) HeapFree(GetProcessHeap(), 0, descr.colorMap);
return result;
}
/***********************************************************************
* X11DRV_DIB_GetDIBits
*/
INT X11DRV_DIB_GetDIBits(
BITMAPOBJ *bmp, DC *dc, UINT startscan,
UINT lines, LPVOID bits, BITMAPINFO *info,
UINT coloruse, HBITMAP hbitmap)
{
X11DRV_DIBSECTION *dib = (X11DRV_DIBSECTION *) bmp->dib;
X11DRV_DIB_IMAGEBITS_DESCR descr;
PALETTEOBJ * palette;
int height;
TRACE("%u scanlines of (%i,%i) -> (%i,%i) starting from %u\n",
lines, bmp->bitmap.bmWidth, bmp->bitmap.bmHeight,
(int)info->bmiHeader.biWidth, (int)info->bmiHeader.biHeight,
startscan );
if (!(palette = (PALETTEOBJ*)GDI_GetObjPtr( dc->hPalette, PALETTE_MAGIC )))
return 0;
if( lines > bmp->bitmap.bmHeight ) lines = bmp->bitmap.bmHeight;
height = info->bmiHeader.biHeight;
if (height < 0) height = -height;
if( lines > height ) lines = height;
/* Top-down images have a negative biHeight, the scanlines of theses images
* were inverted in X11DRV_DIB_GetImageBits_xx
* To prevent this we simply change the sign of lines
* (the number of scan lines to copy).
* Negative lines are correctly handled by X11DRV_DIB_GetImageBits_xx.
*/
if( info->bmiHeader.biHeight < 0 && lines > 0) lines = -lines;
if( startscan >= bmp->bitmap.bmHeight )
{
lines = 0;
goto done;
}
if (DIB_GetBitmapInfo( &info->bmiHeader, &descr.infoWidth, &descr.lines,
&descr.infoBpp, &descr.compression ) == -1)
{
lines = 0;
goto done;
}
switch (descr.infoBpp)
{
case 1:
case 4:
case 8:
case 24:
descr.rMask = descr.gMask = descr.bMask = 0;
break;
case 15:
case 16:
descr.rMask = 0x7c00;
descr.gMask = 0x03e0;
descr.bMask = 0x001f;
break;
case 32:
descr.rMask = 0xff0000;
descr.gMask = 0xff00;
descr.bMask = 0xff;
break;
}
/* Hack for now */
if(!bmp->physBitmap)
X11DRV_CreateBitmap(hbitmap);
descr.dc = dc;
descr.palentry = palette->logpalette.palPalEntry;
descr.bits = bits;
descr.image = NULL;
descr.lines = lines;
descr.depth = bmp->bitmap.bmBitsPixel;
descr.drawable = (Pixmap)bmp->physBitmap;
descr.gc = BITMAP_GC(bmp);
descr.width = bmp->bitmap.bmWidth;
descr.height = bmp->bitmap.bmHeight;
descr.colorMap = info->bmiColors;
descr.xDest = 0;
descr.yDest = 0;
descr.xSrc = 0;
if (descr.lines > 0)
{
descr.ySrc = (descr.height-1) - (startscan + (lines-1));
}
else
{
descr.ySrc = startscan;
}
#ifdef HAVE_LIBXXSHM
descr.useShm = dib ? (dib->shminfo.shmid != -1) : FALSE;
#else
descr.useShm = FALSE;
#endif
descr.dibpitch = dib ? (dib->dibSection.dsBm.bmWidthBytes)
: (((descr.infoWidth * descr.infoBpp + 31) &~31) / 8);
X11DRV_DIB_GetImageBits( &descr );
if(info->bmiHeader.biSizeImage == 0) /* Fill in biSizeImage */
info->bmiHeader.biSizeImage = DIB_GetDIBImageBytes(
info->bmiHeader.biWidth,
info->bmiHeader.biHeight,
info->bmiHeader.biBitCount );
info->bmiHeader.biCompression = 0;
if (descr.compression == BI_BITFIELDS)
{
*(DWORD *)info->bmiColors = descr.rMask;
*((DWORD *)info->bmiColors+1) = descr.gMask;
*((DWORD *)info->bmiColors+2) = descr.bMask;
}
done:
GDI_ReleaseObj( dc->hPalette );
return lines;
}
/***********************************************************************
* DIB_DoProtectDIBSection
*/
static void X11DRV_DIB_DoProtectDIBSection( BITMAPOBJ *bmp, DWORD new_prot )
{
DIBSECTION *dib = bmp->dib;
INT effHeight = dib->dsBm.bmHeight >= 0? dib->dsBm.bmHeight
: -dib->dsBm.bmHeight;
/* use the biSizeImage data as the memory size only if we're dealing with a
compressed image where the value is set. Otherwise, calculate based on
width * height */
INT totalSize = dib->dsBmih.biSizeImage && dib->dsBmih.biCompression != BI_RGB
? dib->dsBmih.biSizeImage
: dib->dsBm.bmWidthBytes * effHeight;
DWORD old_prot;
VirtualProtect(dib->dsBm.bmBits, totalSize, new_prot, &old_prot);
TRACE("Changed protection from %ld to %ld\n", old_prot, new_prot);
}
/***********************************************************************
* X11DRV_DIB_DoUpdateDIBSection
*/
static void X11DRV_DIB_DoCopyDIBSection(BITMAPOBJ *bmp, BOOL toDIB,
void *colorMap, int nColorMap,
Drawable dest,
DWORD xSrc, DWORD ySrc,
DWORD xDest, DWORD yDest,
DWORD width, DWORD height)
{
X11DRV_DIBSECTION *dib = (X11DRV_DIBSECTION *) bmp->dib;
X11DRV_DIB_IMAGEBITS_DESCR descr;
if (DIB_GetBitmapInfo( &dib->dibSection.dsBmih, &descr.infoWidth, &descr.lines,
&descr.infoBpp, &descr.compression ) == -1)
return;
descr.dc = NULL;
descr.palentry = NULL;
descr.image = dib->image;
descr.colorMap = colorMap;
descr.nColorMap = nColorMap;
descr.bits = dib->dibSection.dsBm.bmBits;
descr.depth = bmp->bitmap.bmBitsPixel;
switch (descr.infoBpp)
{
case 1:
case 4:
case 8:
case 24:
descr.rMask = descr.gMask = descr.bMask = 0;
break;
case 15:
case 16:
descr.rMask = (descr.compression == BI_BITFIELDS) ? dib->dibSection.dsBitfields[0] : 0x7c00;
descr.gMask = (descr.compression == BI_BITFIELDS) ? dib->dibSection.dsBitfields[1] : 0x03e0;
descr.bMask = (descr.compression == BI_BITFIELDS) ? dib->dibSection.dsBitfields[2] : 0x001f;
break;
case 32:
descr.rMask = (descr.compression == BI_BITFIELDS) ? dib->dibSection.dsBitfields[0] : 0xff;
descr.gMask = (descr.compression == BI_BITFIELDS) ? dib->dibSection.dsBitfields[1] : 0xff00;
descr.bMask = (descr.compression == BI_BITFIELDS) ? dib->dibSection.dsBitfields[2] : 0xff0000;
break;
}
/* Hack for now */
descr.drawable = dest;
descr.gc = BITMAP_GC(bmp);
descr.xSrc = xSrc;
descr.ySrc = ySrc;
descr.xDest = xDest;
descr.yDest = yDest;
descr.width = width;
descr.height = height;
#ifdef HAVE_LIBXXSHM
descr.useShm = (dib->shminfo.shmid != -1);
#else
descr.useShm = FALSE;
#endif
descr.dibpitch = dib->dibSection.dsBm.bmWidthBytes;
if (toDIB)
{
TRACE("Copying from Pixmap to DIB bits\n");
X11DRV_DIB_GetImageBits( &descr );
}
else
{
TRACE("Copying from DIB bits to Pixmap\n");
X11DRV_DIB_SetImageBits( &descr );
}
}
/***********************************************************************
* X11DRV_DIB_CopyDIBSection
*/
void X11DRV_DIB_CopyDIBSection(DC *dcSrc, DC *dcDst,
DWORD xSrc, DWORD ySrc,
DWORD xDest, DWORD yDest,
DWORD width, DWORD height)
{
BITMAPOBJ *bmp;
X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dcDst->physDev;
int nColorMap = 0, *colorMap = NULL, aColorMap = FALSE;
TRACE("(%p,%p,%ld,%ld,%ld,%ld,%ld,%ld)\n", dcSrc, dcDst,
xSrc, ySrc, xDest, yDest, width, height);
/* this function is meant as an optimization for BitBlt,
* not to be called otherwise */
if (!(dcSrc->flags & DC_MEMORY)) {
ERR("called for non-memory source DC!?\n");
return;
}
bmp = (BITMAPOBJ *)GDI_GetObjPtr( dcSrc->hBitmap, BITMAP_MAGIC );
if (!(bmp && bmp->dib)) {
ERR("called for non-DIBSection!?\n");
GDI_ReleaseObj( dcSrc->hBitmap );
return;
}
/* while BitBlt should already have made sure we only get
* positive values, we should check for oversize values */
if ((xSrc < bmp->bitmap.bmWidth) &&
(ySrc < bmp->bitmap.bmHeight)) {
if (xSrc + width > bmp->bitmap.bmWidth)
width = bmp->bitmap.bmWidth - xSrc;
if (ySrc + height > bmp->bitmap.bmHeight)
height = bmp->bitmap.bmHeight - ySrc;
/* if the source bitmap is 8bpp or less, we're supposed to use the
* DC's palette for color conversion (not the DIB color table) */
if (bmp->dib->dsBm.bmBitsPixel <= 8) {
X11DRV_DIBSECTION *dib = (X11DRV_DIBSECTION *) bmp->dib;
if ((!dcSrc->hPalette) ||
(dcSrc->hPalette == GetStockObject(DEFAULT_PALETTE))) {
/* HACK: no palette has been set in the source DC,
* use the DIB colormap instead - this is necessary in some
* cases since we need to do depth conversion in some places
* where real Windows can just copy data straight over */
colorMap = dib->colorMap;
nColorMap = dib->nColorMap;
} else {
colorMap = X11DRV_DIB_BuildColorMap( dcSrc, (WORD)-1,
bmp->dib->dsBm.bmBitsPixel,
(BITMAPINFO*)&(bmp->dib->dsBmih),
&nColorMap );
if (colorMap) aColorMap = TRUE;
}
}
/* perform the copy */
X11DRV_DIB_DoCopyDIBSection(bmp, FALSE, colorMap, nColorMap,
physDev->drawable, xSrc, ySrc, xDest, yDest,
width, height);
/* free color mapping */
if (aColorMap)
HeapFree(GetProcessHeap(), 0, colorMap);
}
GDI_ReleaseObj( dcSrc->hBitmap );
}
/***********************************************************************
* X11DRV_DIB_DoUpdateDIBSection
*/
static void X11DRV_DIB_DoUpdateDIBSection(BITMAPOBJ *bmp, BOOL toDIB)
{
X11DRV_DIBSECTION *dib = (X11DRV_DIBSECTION *) bmp->dib;
X11DRV_DIB_DoCopyDIBSection(bmp, toDIB, dib->colorMap, dib->nColorMap,
(Drawable)bmp->physBitmap, 0, 0, 0, 0,
bmp->bitmap.bmWidth, bmp->bitmap.bmHeight);
}
/***********************************************************************
* X11DRV_DIB_FaultHandler
*/
static BOOL X11DRV_DIB_FaultHandler( LPVOID res, LPCVOID addr )
{
BITMAPOBJ *bmp;
INT state;
bmp = (BITMAPOBJ *)GDI_GetObjPtr( (HBITMAP)res, BITMAP_MAGIC );
if (!bmp) return FALSE;
state = X11DRV_DIB_Lock(bmp, DIB_Status_None, FALSE);
if (state != DIB_Status_InSync) {
/* no way to tell whether app needs read or write yet,
* try read first */
X11DRV_DIB_Coerce(bmp, DIB_Status_InSync, FALSE);
} else {
/* hm, apparently the app must have write access */
X11DRV_DIB_Coerce(bmp, DIB_Status_AppMod, FALSE);
}
X11DRV_DIB_Unlock(bmp, TRUE);
GDI_ReleaseObj( (HBITMAP)res );
return TRUE;
}
/***********************************************************************
* X11DRV_DIB_Coerce
*/
INT X11DRV_DIB_Coerce(BITMAPOBJ *bmp, INT req, BOOL lossy)
{
X11DRV_DIBSECTION *dib = (X11DRV_DIBSECTION *) bmp->dib;
INT ret = DIB_Status_None;
if (dib) {
EnterCriticalSection(&(dib->lock));
ret = dib->status;
switch (req) {
case DIB_Status_GdiMod:
/* GDI access - request to draw on pixmap */
switch (dib->status)
{
default:
case DIB_Status_None:
dib->p_status = DIB_Status_GdiMod;
X11DRV_DIB_DoUpdateDIBSection( bmp, FALSE );
break;
case DIB_Status_GdiMod:
TRACE("GdiMod requested in status GdiMod\n" );
break;
case DIB_Status_InSync:
TRACE("GdiMod requested in status InSync\n" );
X11DRV_DIB_DoProtectDIBSection( bmp, PAGE_NOACCESS );
dib->status = DIB_Status_GdiMod;
dib->p_status = DIB_Status_InSync;
break;
case DIB_Status_AuxMod:
TRACE("GdiMod requested in status AuxMod\n" );
if (lossy) dib->status = DIB_Status_GdiMod;
else (*dib->copy_aux)(dib->aux_ctx, DIB_Status_GdiMod);
dib->p_status = DIB_Status_AuxMod;
if (dib->status != DIB_Status_AppMod) {
X11DRV_DIB_DoProtectDIBSection( bmp, PAGE_NOACCESS );
break;
}
/* fall through if copy_aux() had to change to AppMod state */
case DIB_Status_AppMod:
TRACE("GdiMod requested in status AppMod\n" );
if (!lossy) {
/* make it readonly to avoid app changing data while we copy */
X11DRV_DIB_DoProtectDIBSection( bmp, PAGE_READONLY );
X11DRV_DIB_DoUpdateDIBSection( bmp, FALSE );
}
X11DRV_DIB_DoProtectDIBSection( bmp, PAGE_NOACCESS );
dib->p_status = DIB_Status_AppMod;
dib->status = DIB_Status_GdiMod;
break;
}
break;
case DIB_Status_InSync:
/* App access - request access to read DIB surface */
/* (typically called from signal handler) */
switch (dib->status)
{
default:
case DIB_Status_None:
/* shouldn't happen from signal handler */
break;
case DIB_Status_AuxMod:
TRACE("InSync requested in status AuxMod\n" );
if (lossy) dib->status = DIB_Status_InSync;
else {
X11DRV_DIB_DoProtectDIBSection( bmp, PAGE_READWRITE );
(*dib->copy_aux)(dib->aux_ctx, DIB_Status_InSync);
}
if (dib->status != DIB_Status_GdiMod) {
X11DRV_DIB_DoProtectDIBSection( bmp, PAGE_READONLY );
break;
}
/* fall through if copy_aux() had to change to GdiMod state */
case DIB_Status_GdiMod:
TRACE("InSync requested in status GdiMod\n" );
if (!lossy) {
X11DRV_DIB_DoProtectDIBSection( bmp, PAGE_READWRITE );
X11DRV_DIB_DoUpdateDIBSection( bmp, TRUE );
}
X11DRV_DIB_DoProtectDIBSection( bmp, PAGE_READONLY );
dib->status = DIB_Status_InSync;
break;
case DIB_Status_InSync:
TRACE("InSync requested in status InSync\n" );
/* shouldn't happen from signal handler */
break;
case DIB_Status_AppMod:
TRACE("InSync requested in status AppMod\n" );
/* no reason to do anything here, and this
* shouldn't happen from signal handler */
break;
}
break;
case DIB_Status_AppMod:
/* App access - request access to write DIB surface */
/* (typically called from signal handler) */
switch (dib->status)
{
default:
case DIB_Status_None:
/* shouldn't happen from signal handler */
break;
case DIB_Status_AuxMod:
TRACE("AppMod requested in status AuxMod\n" );
X11DRV_DIB_DoProtectDIBSection( bmp, PAGE_READWRITE );
if (lossy) dib->status = DIB_Status_AppMod;
else (*dib->copy_aux)(dib->aux_ctx, DIB_Status_AppMod);
if (dib->status != DIB_Status_GdiMod)
break;
/* fall through if copy_aux() had to change to GdiMod state */
case DIB_Status_GdiMod:
TRACE("AppMod requested in status GdiMod\n" );
X11DRV_DIB_DoProtectDIBSection( bmp, PAGE_READWRITE );
if (!lossy) X11DRV_DIB_DoUpdateDIBSection( bmp, TRUE );
dib->status = DIB_Status_AppMod;
break;
case DIB_Status_InSync:
TRACE("AppMod requested in status InSync\n" );
X11DRV_DIB_DoProtectDIBSection( bmp, PAGE_READWRITE );
dib->status = DIB_Status_AppMod;
break;
case DIB_Status_AppMod:
TRACE("AppMod requested in status AppMod\n" );
/* shouldn't happen from signal handler */
break;
}
break;
case DIB_Status_AuxMod:
if (dib->status == DIB_Status_None) {
dib->p_status = req;
} else {
if (dib->status != DIB_Status_AuxMod)
dib->p_status = dib->status;
dib->status = DIB_Status_AuxMod;
}
break;
/* it is up to the caller to do the copy/conversion, probably
* using the return value to decide where to copy from */
}
LeaveCriticalSection(&(dib->lock));
}
return ret;
}
/***********************************************************************
* X11DRV_DIB_Lock
*/
INT X11DRV_DIB_Lock(BITMAPOBJ *bmp, INT req, BOOL lossy)
{
X11DRV_DIBSECTION *dib = (X11DRV_DIBSECTION *) bmp->dib;
INT ret = DIB_Status_None;
if (dib) {
TRACE("Locking %p from thread %08lx\n", bmp, GetCurrentThreadId());
EnterCriticalSection(&(dib->lock));
ret = dib->status;
if (req != DIB_Status_None)
X11DRV_DIB_Coerce(bmp, req, lossy);
}
return ret;
}
/***********************************************************************
* X11DRV_DIB_Unlock
*/
void X11DRV_DIB_Unlock(BITMAPOBJ *bmp, BOOL commit)
{
X11DRV_DIBSECTION *dib = (X11DRV_DIBSECTION *) bmp->dib;
if (dib) {
switch (dib->status)
{
default:
case DIB_Status_None:
/* in case anyone is wondering, this is the "signal handler doesn't
* work" case, where we always have to be ready for app access */
if (commit) {
switch (dib->p_status)
{
case DIB_Status_AuxMod:
TRACE("Unlocking and syncing from AuxMod\n" );
(*dib->copy_aux)(dib->aux_ctx, DIB_Status_AppMod);
if (dib->status != DIB_Status_None) {
dib->p_status = dib->status;
dib->status = DIB_Status_None;
}
if (dib->p_status != DIB_Status_GdiMod)
break;
/* fall through if copy_aux() had to change to GdiMod state */
case DIB_Status_GdiMod:
TRACE("Unlocking and syncing from GdiMod\n" );
X11DRV_DIB_DoUpdateDIBSection( bmp, TRUE );
break;
default:
TRACE("Unlocking without needing to sync\n" );
break;
}
}
else TRACE("Unlocking with no changes\n");
dib->p_status = DIB_Status_None;
break;
case DIB_Status_GdiMod:
TRACE("Unlocking in status GdiMod\n" );
/* DIB was protected in Coerce */
if (!commit) {
/* no commit, revert to InSync if applicable */
if ((dib->p_status == DIB_Status_InSync) ||
(dib->p_status == DIB_Status_AppMod)) {
X11DRV_DIB_DoProtectDIBSection( bmp, PAGE_READONLY );
dib->status = DIB_Status_InSync;
}
}
break;
case DIB_Status_InSync:
TRACE("Unlocking in status InSync\n" );
/* DIB was already protected in Coerce */
break;
case DIB_Status_AppMod:
TRACE("Unlocking in status AppMod\n" );
/* DIB was already protected in Coerce */
/* this case is ordinary only called from the signal handler,
* so we don't bother to check for !commit */
break;
case DIB_Status_AuxMod:
TRACE("Unlocking in status AuxMod\n" );
if (commit) {
/* DIB may need protection now */
if ((dib->p_status == DIB_Status_InSync) ||
(dib->p_status == DIB_Status_AppMod))
X11DRV_DIB_DoProtectDIBSection( bmp, PAGE_NOACCESS );
} else {
/* no commit, revert to previous state */
if (dib->p_status != DIB_Status_None)
dib->status = dib->p_status;
/* no protections changed */
}
dib->p_status = DIB_Status_None;
break;
}
LeaveCriticalSection(&(dib->lock));
TRACE("Unlocked %p\n", bmp);
}
}
/***********************************************************************
* X11DRV_CoerceDIBSection2
*/
INT X11DRV_CoerceDIBSection2(HBITMAP hBmp, INT req, BOOL lossy)
{
BITMAPOBJ *bmp;
INT ret;
bmp = (BITMAPOBJ *)GDI_GetObjPtr( hBmp, BITMAP_MAGIC );
if (!bmp) return DIB_Status_None;
ret = X11DRV_DIB_Coerce(bmp, req, lossy);
GDI_ReleaseObj( hBmp );
return ret;
}
/***********************************************************************
* X11DRV_LockDIBSection2
*/
INT X11DRV_LockDIBSection2(HBITMAP hBmp, INT req, BOOL lossy)
{
BITMAPOBJ *bmp;
INT ret;
bmp = (BITMAPOBJ *)GDI_GetObjPtr( hBmp, BITMAP_MAGIC );
if (!bmp) return DIB_Status_None;
ret = X11DRV_DIB_Lock(bmp, req, lossy);
GDI_ReleaseObj( hBmp );
return ret;
}
/***********************************************************************
* X11DRV_UnlockDIBSection2
*/
void X11DRV_UnlockDIBSection2(HBITMAP hBmp, BOOL commit)
{
BITMAPOBJ *bmp;
bmp = (BITMAPOBJ *)GDI_GetObjPtr( hBmp, BITMAP_MAGIC );
if (!bmp) return;
X11DRV_DIB_Unlock(bmp, commit);
GDI_ReleaseObj( hBmp );
}
/***********************************************************************
* X11DRV_CoerceDIBSection
*/
INT X11DRV_CoerceDIBSection(DC *dc, INT req, BOOL lossy)
{
if (!dc) return DIB_Status_None;
return X11DRV_CoerceDIBSection2( dc->hBitmap, req, lossy );
}
/***********************************************************************
* X11DRV_LockDIBSection
*/
INT X11DRV_LockDIBSection(DC *dc, INT req, BOOL lossy)
{
if (!dc) return DIB_Status_None;
if (!(dc->flags & DC_MEMORY)) return DIB_Status_None;
return X11DRV_LockDIBSection2( dc->hBitmap, req, lossy );
}
/***********************************************************************
* X11DRV_UnlockDIBSection
*/
void X11DRV_UnlockDIBSection(DC *dc, BOOL commit)
{
if (!dc) return;
if (!(dc->flags & DC_MEMORY)) return;
X11DRV_UnlockDIBSection2( dc->hBitmap, commit );
}
#ifdef HAVE_LIBXXSHM
/***********************************************************************
* X11DRV_XShmErrorHandler
*
*/
static int XShmErrorHandler(Display *dpy, XErrorEvent *event)
{
XShmErrorFlag = 1;
return 0;
}
/***********************************************************************
* X11DRV_XShmCreateImage
*
*/
static XImage *X11DRV_XShmCreateImage( int width, int height, int bpp,
XShmSegmentInfo* shminfo)
{
int (*WineXHandler)(Display *, XErrorEvent *);
XImage *image;
wine_tsx11_lock();
image = XShmCreateImage(gdi_display, visual, bpp, ZPixmap, NULL, shminfo, width, height);
if (image)
{
shminfo->shmid = shmget(IPC_PRIVATE, image->bytes_per_line * height,
IPC_CREAT|0700);
if( shminfo->shmid != -1 )
{
shminfo->shmaddr = image->data = shmat(shminfo->shmid, 0, 0);
if( shminfo->shmaddr != (char*)-1 )
{
shminfo->readOnly = FALSE;
if( XShmAttach( gdi_display, shminfo ) != 0)
{
/* Reset the error flag */
XShmErrorFlag = 0;
WineXHandler = XSetErrorHandler(XShmErrorHandler);
XSync( gdi_display, 0 );
if (!XShmErrorFlag)
{
shmctl(shminfo->shmid, IPC_RMID, 0);
XSetErrorHandler(WineXHandler);
wine_tsx11_unlock();
return image; /* Success! */
}
/* An error occured */
XShmErrorFlag = 0;
XSetErrorHandler(WineXHandler);
}
shmdt(shminfo->shmaddr);
}
shmctl(shminfo->shmid, IPC_RMID, 0);
}
XFlush(gdi_display);
XDestroyImage(image);
image = NULL;
}
wine_tsx11_unlock();
return image;
}
#endif /* HAVE_LIBXXSHM */
/***********************************************************************
* X11DRV_DIB_CreateDIBSection
*/
HBITMAP X11DRV_DIB_CreateDIBSection(
DC *dc, BITMAPINFO *bmi, UINT usage,
LPVOID *bits, HANDLE section,
DWORD offset, DWORD ovr_pitch)
{
HBITMAP res = 0;
BITMAPOBJ *bmp = NULL;
X11DRV_DIBSECTION *dib = NULL;
int *colorMap = NULL;
int nColorMap;
/* Fill BITMAP32 structure with DIB data */
BITMAPINFOHEADER *bi = &bmi->bmiHeader;
INT effHeight, totalSize;
BITMAP bm;
LPVOID mapBits = NULL;
TRACE("format (%ld,%ld), planes %d, bpp %d, size %ld, colors %ld (%s)\n",
bi->biWidth, bi->biHeight, bi->biPlanes, bi->biBitCount,
bi->biSizeImage, bi->biClrUsed, usage == DIB_PAL_COLORS? "PAL" : "RGB");
effHeight = bi->biHeight >= 0 ? bi->biHeight : -bi->biHeight;
bm.bmType = 0;
bm.bmWidth = bi->biWidth;
bm.bmHeight = effHeight;
bm.bmWidthBytes = ovr_pitch ? ovr_pitch
: DIB_GetDIBWidthBytes(bm.bmWidth, bi->biBitCount);
bm.bmPlanes = bi->biPlanes;
bm.bmBitsPixel = bi->biBitCount;
bm.bmBits = NULL;
/* Get storage location for DIB bits. Only use biSizeImage if it's valid and
we're dealing with a compressed bitmap. Otherwise, use width * height. */
totalSize = bi->biSizeImage && bi->biCompression != BI_RGB
? bi->biSizeImage : bm.bmWidthBytes * effHeight;
if (section)
{
SYSTEM_INFO SystemInfo;
DWORD mapOffset;
INT mapSize;
GetSystemInfo( &SystemInfo );
mapOffset = offset - (offset % SystemInfo.dwAllocationGranularity);
mapSize = totalSize + (offset - mapOffset);
mapBits = MapViewOfFile( section,
FILE_MAP_ALL_ACCESS,
0L,
mapOffset,
mapSize );
bm.bmBits = (char *)mapBits + (offset - mapOffset);
}
else if (ovr_pitch && offset)
bm.bmBits = (LPVOID) offset;
else {
offset = 0;
bm.bmBits = VirtualAlloc(NULL, totalSize,
MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
}
/* Create Color Map */
if (bm.bmBits && bm.bmBitsPixel <= 8)
colorMap = X11DRV_DIB_BuildColorMap( usage == DIB_PAL_COLORS? dc : NULL,
usage, bm.bmBitsPixel, bmi, &nColorMap );
/* Allocate Memory for DIB and fill structure */
if (bm.bmBits)
dib = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(X11DRV_DIBSECTION));
if (dib)
{
dib->dibSection.dsBm = bm;
dib->dibSection.dsBmih = *bi;
dib->dibSection.dsBmih.biSizeImage = totalSize;
/* Set dsBitfields values */
if ( usage == DIB_PAL_COLORS || bi->biBitCount <= 8)
{
dib->dibSection.dsBitfields[0] = dib->dibSection.dsBitfields[1] = dib->dibSection.dsBitfields[2] = 0;
}
else switch( bi->biBitCount )
{
case 16:
dib->dibSection.dsBitfields[0] = (bi->biCompression == BI_BITFIELDS) ? *(DWORD *)bmi->bmiColors : 0x7c00;
dib->dibSection.dsBitfields[1] = (bi->biCompression == BI_BITFIELDS) ? *((DWORD *)bmi->bmiColors + 1) : 0x03e0;
dib->dibSection.dsBitfields[2] = (bi->biCompression == BI_BITFIELDS) ? *((DWORD *)bmi->bmiColors + 2) : 0x001f;
break;
case 24:
dib->dibSection.dsBitfields[0] = 0xff;
dib->dibSection.dsBitfields[1] = 0xff00;
dib->dibSection.dsBitfields[2] = 0xff0000;
break;
case 32:
dib->dibSection.dsBitfields[0] = (bi->biCompression == BI_BITFIELDS) ? *(DWORD *)bmi->bmiColors : 0xff;
dib->dibSection.dsBitfields[1] = (bi->biCompression == BI_BITFIELDS) ? *((DWORD *)bmi->bmiColors + 1) : 0xff00;
dib->dibSection.dsBitfields[2] = (bi->biCompression == BI_BITFIELDS) ? *((DWORD *)bmi->bmiColors + 2) : 0xff0000;
break;
}
dib->dibSection.dshSection = section;
dib->dibSection.dsOffset = offset;
dib->status = DIB_Status_None;
dib->nColorMap = nColorMap;
dib->colorMap = colorMap;
}
/* Create Device Dependent Bitmap and add DIB pointer */
if (dib)
{
res = CreateDIBitmap(dc->hSelf, bi, 0, NULL, bmi, usage);
if (res)
{
bmp = (BITMAPOBJ *) GDI_GetObjPtr(res, BITMAP_MAGIC);
if (bmp)
{
bmp->dib = (DIBSECTION *) dib;
/* HACK for now */
if(!bmp->physBitmap)
X11DRV_CreateBitmap(res);
}
}
}
/* Create XImage */
if (dib && bmp)
{
#ifdef HAVE_LIBXXSHM
if (TSXShmQueryExtension(gdi_display) &&
(dib->image = X11DRV_XShmCreateImage( bm.bmWidth, effHeight,
bmp->bitmap.bmBitsPixel, &dib->shminfo )) )
{
; /* Created Image */
} else {
dib->image = X11DRV_DIB_CreateXImage( bm.bmWidth, effHeight, bmp->bitmap.bmBitsPixel );
dib->shminfo.shmid = -1;
}
#else
dib->image = X11DRV_DIB_CreateXImage( bm.bmWidth, effHeight, bmp->bitmap.bmBitsPixel );
#endif
}
/* Clean up in case of errors */
if (!res || !bmp || !dib || !bm.bmBits || (bm.bmBitsPixel <= 8 && !colorMap))
{
TRACE("got an error res=%08x, bmp=%p, dib=%p, bm.bmBits=%p\n",
res, bmp, dib, bm.bmBits);
if (bm.bmBits)
{
if (section)
UnmapViewOfFile(mapBits), bm.bmBits = NULL;
else if (!offset)
VirtualFree(bm.bmBits, 0L, MEM_RELEASE), bm.bmBits = NULL;
}
if (dib && dib->image) { XDestroyImage(dib->image); dib->image = NULL; }
if (colorMap) { HeapFree(GetProcessHeap(), 0, colorMap); colorMap = NULL; }
if (dib) { HeapFree(GetProcessHeap(), 0, dib); dib = NULL; }
if (bmp) { GDI_ReleaseObj(res); bmp = NULL; }
if (res) { DeleteObject(res); res = 0; }
}
else if (bm.bmBits)
{
/* Install fault handler, if possible */
InitializeCriticalSection(&(dib->lock));
if (VIRTUAL_SetFaultHandler(bm.bmBits, X11DRV_DIB_FaultHandler, (LPVOID)res))
{
if (section || offset)
{
X11DRV_DIB_DoProtectDIBSection( bmp, PAGE_READWRITE );
if (dib) dib->status = DIB_Status_AppMod;
}
else
{
X11DRV_DIB_DoProtectDIBSection( bmp, PAGE_READONLY );
if (dib) dib->status = DIB_Status_InSync;
}
}
}
/* Return BITMAP handle and storage location */
if (bmp) GDI_ReleaseObj(res);
if (bm.bmBits && bits) *bits = bm.bmBits;
return res;
}
/***********************************************************************
* X11DRV_DIB_DeleteDIBSection
*/
void X11DRV_DIB_DeleteDIBSection(BITMAPOBJ *bmp)
{
X11DRV_DIBSECTION *dib = (X11DRV_DIBSECTION *) bmp->dib;
if (dib->image)
{
#ifdef HAVE_LIBXXSHM
if (dib->shminfo.shmid != -1)
{
TSXShmDetach (gdi_display, &(dib->shminfo));
XDestroyImage (dib->image);
shmdt (dib->shminfo.shmaddr);
dib->shminfo.shmid = -1;
}
else
#endif
XDestroyImage( dib->image );
}
if (dib->colorMap)
HeapFree(GetProcessHeap(), 0, dib->colorMap);
DeleteCriticalSection(&(dib->lock));
}
/***********************************************************************
* X11DRV_DIB_SetDIBColorTable
*/
UINT X11DRV_DIB_SetDIBColorTable(BITMAPOBJ *bmp, DC *dc, UINT start, UINT count, const RGBQUAD *colors)
{
X11DRV_DIBSECTION *dib = (X11DRV_DIBSECTION *) bmp->dib;
if (dib && dib->colorMap) {
/*
* Changing color table might change the mapping between
* DIB colors and X11 colors and thus alter the visible state
* of the bitmap object.
*/
X11DRV_DIB_Lock(bmp, DIB_Status_AppMod, FALSE);
X11DRV_DIB_GenColorMap( dc, dib->colorMap, DIB_RGB_COLORS,
dib->dibSection.dsBm.bmBitsPixel,
TRUE, colors, start, count + start );
X11DRV_DIB_Unlock(bmp, TRUE);
return count;
}
return 0;
}
/***********************************************************************
* X11DRV_DIB_GetDIBColorTable
*/
UINT X11DRV_DIB_GetDIBColorTable(BITMAPOBJ *bmp, DC *dc, UINT start, UINT count, RGBQUAD *colors)
{
X11DRV_DIBSECTION *dib = (X11DRV_DIBSECTION *) bmp->dib;
if (dib && dib->colorMap) {
int i, end = count + start;
if (end > dib->nColorMap) end = dib->nColorMap;
for (i = start; i < end; i++,colors++) {
COLORREF col = X11DRV_PALETTE_ToLogical( dib->colorMap[i] );
colors->rgbBlue = GetBValue(col);
colors->rgbGreen = GetGValue(col);
colors->rgbRed = GetRValue(col);
colors->rgbReserved = 0;
}
return end-start;
}
return 0;
}
/**************************************************************************
* X11DRV_DIB_CreateDIBFromPixmap
*
* Allocates a packed DIB and copies the Pixmap data into it.
* If bDeletePixmap is TRUE, the Pixmap passed in is deleted after the conversion.
*/
HGLOBAL X11DRV_DIB_CreateDIBFromPixmap(Pixmap pixmap, HDC hdc, BOOL bDeletePixmap)
{
HBITMAP hBmp = 0;
BITMAPOBJ *pBmp = NULL;
HGLOBAL hPackedDIB = 0;
/* Allocates an HBITMAP which references the Pixmap passed to us */
hBmp = X11DRV_BITMAP_CreateBitmapHeaderFromPixmap(pixmap);
if (!hBmp)
{
TRACE("\tCould not create bitmap header for Pixmap\n");
goto END;
}
/*
* Create a packed DIB from the Pixmap wrapper bitmap created above.
* A packed DIB contains a BITMAPINFO structure followed immediately by
* an optional color palette and the pixel data.
*/
hPackedDIB = DIB_CreateDIBFromBitmap(hdc, hBmp);
/* Get a pointer to the BITMAPOBJ structure */
pBmp = (BITMAPOBJ *)GDI_GetObjPtr( hBmp, BITMAP_MAGIC );
/* We can now get rid of the HBITMAP wrapper we created earlier.
* Note: Simply calling DeleteObject will free the embedded Pixmap as well.
*/
if (!bDeletePixmap)
{
/* Clear the physBitmap to prevent the Pixmap from being deleted by DeleteObject */
pBmp->physBitmap = NULL;
pBmp->funcs = NULL;
}
GDI_ReleaseObj( hBmp );
DeleteObject(hBmp);
END:
TRACE("\tReturning packed DIB %x\n", hPackedDIB);
return hPackedDIB;
}
/**************************************************************************
* X11DRV_DIB_CreatePixmapFromDIB
*
* Creates a Pixmap from a packed DIB
*/
Pixmap X11DRV_DIB_CreatePixmapFromDIB( HGLOBAL hPackedDIB, HDC hdc )
{
Pixmap pixmap = None;
HBITMAP hBmp = 0;
BITMAPOBJ *pBmp = NULL;
LPBYTE pPackedDIB = NULL;
LPBITMAPINFO pbmi = NULL;
LPBITMAPINFOHEADER pbmiHeader = NULL;
LPBYTE pbits = NULL;
/* Get a pointer to the packed DIB's data */
pPackedDIB = (LPBYTE)GlobalLock(hPackedDIB);
pbmiHeader = (LPBITMAPINFOHEADER)pPackedDIB;
pbmi = (LPBITMAPINFO)pPackedDIB;
pbits = (LPBYTE)(pPackedDIB
+ DIB_BitmapInfoSize( (LPBITMAPINFO)pbmiHeader, DIB_RGB_COLORS ));
/* Create a DDB from the DIB */
hBmp = CreateDIBitmap(hdc,
pbmiHeader,
CBM_INIT,
(LPVOID)pbits,
pbmi,
DIB_RGB_COLORS);
GlobalUnlock(hPackedDIB);
TRACE("CreateDIBitmap returned %x\n", hBmp);
/* Retrieve the internal Pixmap from the DDB */
pBmp = (BITMAPOBJ *) GDI_GetObjPtr( hBmp, BITMAP_MAGIC );
pixmap = (Pixmap)pBmp->physBitmap;
/* clear the physBitmap so that we can steal its pixmap */
pBmp->physBitmap = NULL;
pBmp->funcs = NULL;
/* Delete the DDB we created earlier now that we have stolen its pixmap */
GDI_ReleaseObj( hBmp );
DeleteObject(hBmp);
TRACE("\tReturning Pixmap %ld\n", pixmap);
return pixmap;
}