wine/dlls/winex11.drv/dib.c
Rob Shearman 428ada3c8a winex11.drv: Optimise getting the bits of a DIB after calling SetDIBits.
Sync the application's bits in SetDIBits if the input bits are in 
exactly the same format and the size of the image is small enough not to 
cause a performance hit (in case the application doesn't get ever access 
the bits directly).
2008-02-22 11:52:08 +01:00

4951 lines
178 KiB
C

/*
* X11DRV device-independent bitmaps
*
* Copyright 1993,1994 Alexandre Julliard
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "config.h"
#include "wine/port.h"
#include <X11/Xlib.h>
#ifdef HAVE_LIBXXSHM
#include <X11/extensions/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 <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include "windef.h"
#include "winbase.h"
#include "wingdi.h"
#include "x11drv.h"
#include "excpt.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(bitmap);
static struct list dibs_list = LIST_INIT(dibs_list);
static CRITICAL_SECTION dibs_cs;
static CRITICAL_SECTION_DEBUG dibs_cs_debug =
{
0, 0, &dibs_cs,
{ &dibs_cs_debug.ProcessLocksList, &dibs_cs_debug.ProcessLocksList },
0, 0, { (DWORD_PTR)(__FILE__ ": dibs_cs") }
};
static CRITICAL_SECTION dibs_cs = { &dibs_cs_debug, -1, 0, 0, 0, 0 };
static PVOID dibs_handler;
static int ximageDepthTable[32];
/* This structure holds the arguments for DIB_SetImageBits() */
typedef struct
{
X11DRV_PDEVICE *physDev;
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;
DWORD sizeImage;
} X11DRV_DIB_IMAGEBITS_DESCR;
enum Rle_EscapeCodes
{
RLE_EOL = 0, /* End of line */
RLE_END = 1, /* End of bitmap */
RLE_DELTA = 2 /* Delta */
};
static INT X11DRV_DIB_Coerce(X_PHYSBITMAP *,INT);
static INT X11DRV_DIB_Lock(X_PHYSBITMAP *,INT);
static void X11DRV_DIB_Unlock(X_PHYSBITMAP *,BOOL);
/*
Some of the following helper functions are duplicated in
dlls/gdi/dib.c
*/
/***********************************************************************
* DIB_DoProtectDIBSection
*/
static void X11DRV_DIB_DoProtectDIBSection( X_PHYSBITMAP *physBitmap, DWORD new_prot )
{
DWORD old_prot;
VirtualProtect(physBitmap->base, physBitmap->size, new_prot, &old_prot);
TRACE("Changed protection from %d to %d\n", old_prot, new_prot);
}
/***********************************************************************
* X11DRV_DIB_GetXImageWidthBytes
*
* Return the width of an X image in bytes
*/
static inline 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_GetDIBWidthBytes
*
* Return the width of a DIB bitmap in bytes. DIB bitmap data is 32-bit aligned.
*/
static int X11DRV_DIB_GetDIBWidthBytes( int width, int depth )
{
int words;
switch(depth)
{
case 1: words = (width + 31) / 32; break;
case 4: words = (width + 7) / 8; break;
case 8: words = (width + 3) / 4; break;
case 15:
case 16: words = (width + 1) / 2; break;
case 24: words = (width * 3 + 3) / 4; break;
default:
WARN("(%d): Unsupported depth\n", depth );
/* fall through */
case 32:
words = width;
}
return 4 * words;
}
/***********************************************************************
* X11DRV_DIB_GetDIBImageBytes
*
* Return the number of bytes used to hold the image in a DIB bitmap.
*/
static int X11DRV_DIB_GetDIBImageBytes( int width, int height, int depth )
{
return X11DRV_DIB_GetDIBWidthBytes( width, depth ) * abs( height );
}
/***********************************************************************
* X11DRV_DIB_BitmapInfoSize
*
* Return the size of the bitmap info structure including color table.
*/
int X11DRV_DIB_BitmapInfoSize( const BITMAPINFO * info, WORD coloruse )
{
unsigned int colors;
if (info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
{
const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *)info;
colors = (core->bcBitCount <= 8) ? 1 << core->bcBitCount : 0;
return sizeof(BITMAPCOREHEADER) + colors *
((coloruse == DIB_RGB_COLORS) ? sizeof(RGBTRIPLE) : sizeof(WORD));
}
else /* assume BITMAPINFOHEADER */
{
colors = info->bmiHeader.biClrUsed;
if (!colors && (info->bmiHeader.biBitCount <= 8))
colors = 1 << info->bmiHeader.biBitCount;
return sizeof(BITMAPINFOHEADER) + colors *
((coloruse == DIB_RGB_COLORS) ? sizeof(RGBQUAD) : sizeof(WORD));
}
}
/***********************************************************************
* 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;
}
/***********************************************************************
* DIB_GetBitmapInfoEx
*
* Get the info from a bitmap header.
* Return 1 for INFOHEADER, 0 for COREHEADER, -1 for error.
*/
static int DIB_GetBitmapInfoEx( const BITMAPINFOHEADER *header, LONG *width,
LONG *height, WORD *planes, WORD *bpp,
WORD *compr, DWORD *size )
{
if (header->biSize == sizeof(BITMAPCOREHEADER))
{
const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *)header;
*width = core->bcWidth;
*height = core->bcHeight;
*planes = core->bcPlanes;
*bpp = core->bcBitCount;
*compr = 0;
*size = 0;
return 0;
}
if (header->biSize >= sizeof(BITMAPINFOHEADER))
{
*width = header->biWidth;
*height = header->biHeight;
*planes = header->biPlanes;
*bpp = header->biBitCount;
*compr = header->biCompression;
*size = header->biSizeImage;
return 1;
}
ERR("(%d): unknown/wrong size for header\n", header->biSize );
return -1;
}
/***********************************************************************
* X11DRV_DIB_GetColorCount
*
* Computes the number of colors for the bitmap palette.
* Should not be called for a >8-bit deep bitmap.
*/
static unsigned int X11DRV_DIB_GetColorCount(const BITMAPINFO *info)
{
unsigned int colors;
BOOL core_info = info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER);
if (core_info)
{
colors = 1 << ((const BITMAPCOREINFO*)info)->bmciHeader.bcBitCount;
}
else
{
colors = info->bmiHeader.biClrUsed;
if (!colors) colors = 1 << info->bmiHeader.biBitCount;
}
if (colors > 256)
{
ERR("called with >256 colors!\n");
colors = 0;
}
return colors;
}
/***********************************************************************
* DIB_GetBitmapInfo
*
* Get the info from a bitmap header.
* Return 1 for INFOHEADER, 0 for COREHEADER, -1 for error.
*/
static int DIB_GetBitmapInfo( const BITMAPINFOHEADER *header, LONG *width,
LONG *height, WORD *bpp, WORD *compr )
{
WORD planes;
DWORD size;
return DIB_GetBitmapInfoEx( header, width, height, &planes, bpp, compr, &size);
}
static inline BOOL colour_is_brighter(RGBQUAD c1, RGBQUAD c2)
{
return (c1.rgbRed * c1.rgbRed + c1.rgbGreen * c1.rgbGreen + c1.rgbBlue * c1.rgbBlue) >
(c2.rgbRed * c2.rgbRed + c2.rgbGreen * c2.rgbGreen + c2.rgbBlue * c2.rgbBlue);
}
/***********************************************************************
* X11DRV_DIB_GenColorMap
*
* Fills the color map of a bitmap palette. Should not be called
* for a >8-bit deep bitmap.
*/
static int *X11DRV_DIB_GenColorMap( X11DRV_PDEVICE *physDev, int *colorMapping,
WORD coloruse, WORD depth, BOOL quads,
const void *colorPtr, int start, int end )
{
int i;
if (coloruse == DIB_RGB_COLORS)
{
if (quads)
{
const RGBQUAD * rgb = (const RGBQUAD *)colorPtr;
if (depth == 1) /* Monochrome */
{
BOOL invert = FALSE;
RGBQUAD table[2];
if (GetDIBColorTable( physDev->hdc, 0, 2, table ) == 2)
invert = !colour_is_brighter(table[1], table[0]);
for (i = start; i < end; i++, rgb++)
colorMapping[i] = ((rgb->rgbRed + rgb->rgbGreen +
rgb->rgbBlue > 255*3/2 && !invert) ||
(rgb->rgbRed + rgb->rgbGreen +
rgb->rgbBlue <= 255*3/2 && invert));
}
else
for (i = start; i < end; i++, rgb++)
colorMapping[i] = X11DRV_PALETTE_ToPhysical( NULL, RGB(rgb->rgbRed,
rgb->rgbGreen,
rgb->rgbBlue));
}
else
{
const RGBTRIPLE * rgb = (const RGBTRIPLE *)colorPtr;
if (depth == 1) /* Monochrome */
{
BOOL invert = FALSE;
RGBQUAD table[2];
if (GetDIBColorTable( physDev->hdc, 0, 2, table ) == 2)
invert = !colour_is_brighter(table[1], table[0]);
for (i = start; i < end; i++, rgb++)
colorMapping[i] = ((rgb->rgbtRed + rgb->rgbtGreen +
rgb->rgbtBlue > 255*3/2 && !invert) ||
(rgb->rgbtRed + rgb->rgbtGreen +
rgb->rgbtBlue <= 255*3/2 && invert));
}
else
for (i = start; i < end; i++, rgb++)
colorMapping[i] = X11DRV_PALETTE_ToPhysical( NULL, RGB(rgb->rgbtRed,
rgb->rgbtGreen,
rgb->rgbtBlue));
}
}
else /* DIB_PAL_COLORS */
{
const WORD * index = (const WORD *)colorPtr;
for (i = start; i < end; i++, index++)
colorMapping[i] = X11DRV_PALETTE_ToPhysical( physDev, PALETTEINDEX(*index) );
}
return colorMapping;
}
/***********************************************************************
* X11DRV_DIB_BuildColorMap
*
* Build the color map from the bitmap palette. Should not be called
* for a >8-bit deep bitmap.
*/
static int *X11DRV_DIB_BuildColorMap( X11DRV_PDEVICE *physDev, WORD coloruse, WORD depth,
const BITMAPINFO *info, int *nColors )
{
BOOL isInfo;
const void *colorPtr;
int *colorMapping;
*nColors = X11DRV_DIB_GetColorCount(info);
if (!*nColors) return NULL;
isInfo = info->bmiHeader.biSize != sizeof(BITMAPCOREHEADER);
colorPtr = (const BYTE*)info + (WORD)info->bmiHeader.biSize;
if (!(colorMapping = HeapAlloc(GetProcessHeap(), 0, *nColors * sizeof(int) )))
return NULL;
return X11DRV_DIB_GenColorMap( physDev, colorMapping, coloruse, depth,
isInfo, colorPtr, 0, *nColors);
}
/***********************************************************************
* X11DRV_DIB_MapColor
*/
static int X11DRV_DIB_MapColor( int *physMap, int nPhysMap, int phys, int oldcol )
{
unsigned 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_MaskToShift
*
* Helper for X11DRV_DIB_GetDIBits.
* Returns the by how many bits to shift a given color so that it is
* in the proper position.
*/
INT X11DRV_DIB_MaskToShift(DWORD mask)
{
int shift;
if (mask==0)
return 0;
shift=0;
while ((mask&1)==0) {
mask>>=1;
shift++;
}
return shift;
}
/***********************************************************************
* X11DRV_DIB_CheckMask
*
* Check RGB mask if it is either 0 or matches visual's mask.
*/
static inline int X11DRV_DIB_CheckMask(int red_mask, int green_mask, int blue_mask)
{
return ( red_mask == 0 && green_mask == 0 && blue_mask == 0 ) ||
( red_mask == visual->red_mask && green_mask == visual->green_mask &&
blue_mask == visual->blue_mask );
}
/***********************************************************************
* 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, width;
const BYTE* srcbyte;
BYTE srcval, extra;
DWORD i, x;
if (lines < 0 ) {
lines = -lines;
srcbits = srcbits + linebytes * (lines - 1);
linebytes = -linebytes;
}
if ((extra = (left & 7)) != 0) {
left &= ~7;
dstwidth += extra;
}
srcbits += left >> 3;
width = min(srcwidth, dstwidth);
/* ==== pal 1 dib -> any bmp format ==== */
for (h = lines-1; h >=0; h--) {
srcbyte=srcbits;
for (i = width/8, x = left; i > 0; i--) {
srcval=*srcbyte++;
XPutPixel( bmpImage, x++, h, colors[ srcval >> 7] );
XPutPixel( bmpImage, x++, h, colors[(srcval >> 6) & 1] );
XPutPixel( bmpImage, x++, h, colors[(srcval >> 5) & 1] );
XPutPixel( bmpImage, x++, h, colors[(srcval >> 4) & 1] );
XPutPixel( bmpImage, x++, h, colors[(srcval >> 3) & 1] );
XPutPixel( bmpImage, x++, h, colors[(srcval >> 2) & 1] );
XPutPixel( bmpImage, x++, h, colors[(srcval >> 1) & 1] );
XPutPixel( bmpImage, x++, h, colors[ srcval & 1] );
}
if (width % 8){
srcval=*srcbyte;
switch (width & 7)
{
case 7: XPutPixel(bmpImage, x++, h, colors[srcval >> 7]); srcval<<=1;
case 6: XPutPixel(bmpImage, x++, h, colors[srcval >> 7]); srcval<<=1;
case 5: XPutPixel(bmpImage, x++, h, colors[srcval >> 7]); srcval<<=1;
case 4: XPutPixel(bmpImage, x++, h, colors[srcval >> 7]); srcval<<=1;
case 3: XPutPixel(bmpImage, x++, h, colors[srcval >> 7]); srcval<<=1;
case 2: XPutPixel(bmpImage, x++, h, colors[srcval >> 7]); srcval<<=1;
case 1: XPutPixel(bmpImage, x++, h, colors[srcval >> 7]);
}
}
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, width = min(dstwidth, srcwidth);
if (lines < 0 ) {
lines = -lines;
dstbits = dstbits + linebytes * (lines - 1);
linebytes = -linebytes;
}
switch (bmpImage->depth)
{
case 1:
case 4:
if (X11DRV_DIB_CheckMask(bmpImage->red_mask,bmpImage->green_mask,bmpImage->blue_mask)
&& srccolors) {
/* ==== pal 1 or 4 bmp -> pal 1 dib ==== */
BYTE* dstbyte;
for (h=lines-1; h>=0; h--) {
BYTE dstval;
dstbyte=dstbits;
dstval=0;
for (x=0; x<width; x++) {
PALETTEENTRY srcval;
srcval=srccolors[XGetPixel(bmpImage, x, h)];
dstval|=(X11DRV_DIB_GetNearestIndex
(colors, 2,
srcval.peRed,
srcval.peGreen,
srcval.peBlue) << (7 - (x & 7)));
if ((x&7)==7) {
*dstbyte++=dstval;
dstval=0;
}
}
if ((width&7)!=0) {
*dstbyte=dstval;
}
dstbits += linebytes;
}
} else {
goto notsupported;
}
break;
case 8:
if (X11DRV_DIB_CheckMask(bmpImage->red_mask, bmpImage->green_mask, bmpImage->blue_mask)
&& srccolors) {
/* ==== pal 8 bmp -> pal 1 dib ==== */
const void* srcbits;
const BYTE* srcpixel;
BYTE* dstbyte;
srcbits=bmpImage->data+(lines-1)*bmpImage->bytes_per_line;
for (h=0; h<lines; h++) {
BYTE dstval;
srcpixel=srcbits;
dstbyte=dstbits;
dstval=0;
for (x=0; x<width; x++) {
PALETTEENTRY srcval;
srcval=srccolors[*srcpixel++];
dstval|=(X11DRV_DIB_GetNearestIndex
(colors, 2,
srcval.peRed,
srcval.peGreen,
srcval.peBlue) << (7-(x&7)) );
if ((x&7)==7) {
*dstbyte++=dstval;
dstval=0;
}
}
if ((width&7)!=0) {
*dstbyte=dstval;
}
srcbits = (const char*)srcbits - bmpImage->bytes_per_line;
dstbits += linebytes;
}
} else {
goto notsupported;
}
break;
case 15:
case 16:
{
const void* srcbits;
const WORD* srcpixel;
BYTE* dstbyte;
srcbits=bmpImage->data+(lines-1)*bmpImage->bytes_per_line;
if (bmpImage->green_mask==0x03e0) {
if (bmpImage->red_mask==0x7c00) {
/* ==== rgb 555 bmp -> pal 1 dib ==== */
for (h=0; h<lines; h++) {
BYTE dstval;
srcpixel=srcbits;
dstbyte=dstbits;
dstval=0;
for (x=0; x<width; x++) {
WORD srcval;
srcval=*srcpixel++;
dstval|=(X11DRV_DIB_GetNearestIndex
(colors, 2,
((srcval >> 7) & 0xf8) | /* r */
((srcval >> 12) & 0x07),
((srcval >> 2) & 0xf8) | /* g */
((srcval >> 7) & 0x07),
((srcval << 3) & 0xf8) | /* b */
((srcval >> 2) & 0x07) ) << (7-(x&7)) );
if ((x&7)==7) {
*dstbyte++=dstval;
dstval=0;
}
}
if ((width&7)!=0) {
*dstbyte=dstval;
}
srcbits = (const char*)srcbits - bmpImage->bytes_per_line;
dstbits += linebytes;
}
} else if (bmpImage->blue_mask==0x7c00) {
/* ==== bgr 555 bmp -> pal 1 dib ==== */
for (h=0; h<lines; h++) {
WORD dstval;
srcpixel=srcbits;
dstbyte=dstbits;
dstval=0;
for (x=0; x<width; x++) {
BYTE srcval;
srcval=*srcpixel++;
dstval|=(X11DRV_DIB_GetNearestIndex
(colors, 2,
((srcval << 3) & 0xf8) | /* r */
((srcval >> 2) & 0x07),
((srcval >> 2) & 0xf8) | /* g */
((srcval >> 7) & 0x07),
((srcval >> 7) & 0xf8) | /* b */
((srcval >> 12) & 0x07) ) << (7-(x&7)) );
if ((x&7)==7) {
*dstbyte++=dstval;
dstval=0;
}
}
if ((width&7)!=0) {
*dstbyte=dstval;
}
srcbits = (const char*)srcbits - bmpImage->bytes_per_line;
dstbits += linebytes;
}
} else {
goto notsupported;
}
} else if (bmpImage->green_mask==0x07e0) {
if (bmpImage->red_mask==0xf800) {
/* ==== rgb 565 bmp -> pal 1 dib ==== */
for (h=0; h<lines; h++) {
BYTE dstval;
srcpixel=srcbits;
dstbyte=dstbits;
dstval=0;
for (x=0; x<width; x++) {
WORD srcval;
srcval=*srcpixel++;
dstval|=(X11DRV_DIB_GetNearestIndex
(colors, 2,
((srcval >> 8) & 0xf8) | /* r */
((srcval >> 13) & 0x07),
((srcval >> 3) & 0xfc) | /* g */
((srcval >> 9) & 0x03),
((srcval << 3) & 0xf8) | /* b */
((srcval >> 2) & 0x07) ) << (7-(x&7)) );
if ((x&7)==7) {
*dstbyte++=dstval;
dstval=0;
}
}
if ((width&7)!=0) {
*dstbyte=dstval;
}
srcbits = (const char*)srcbits - bmpImage->bytes_per_line;
dstbits += linebytes;
}
} else if (bmpImage->blue_mask==0xf800) {
/* ==== bgr 565 bmp -> pal 1 dib ==== */
for (h=0; h<lines; h++) {
BYTE dstval;
srcpixel=srcbits;
dstbyte=dstbits;
dstval=0;
for (x=0; x<width; x++) {
WORD srcval;
srcval=*srcpixel++;
dstval|=(X11DRV_DIB_GetNearestIndex
(colors, 2,
((srcval << 3) & 0xf8) | /* r */
((srcval >> 2) & 0x07),
((srcval >> 3) & 0xfc) | /* g */
((srcval >> 9) & 0x03),
((srcval >> 8) & 0xf8) | /* b */
((srcval >> 13) & 0x07) ) << (7-(x&7)) );
if ((x&7)==7) {
*dstbyte++=dstval;
dstval=0;
}
}
if ((width&7)!=0) {
*dstbyte=dstval;
}
srcbits = (const char*)srcbits - bmpImage->bytes_per_line;
dstbits += linebytes;
}
} else {
goto notsupported;
}
} else {
goto notsupported;
}
}
break;
case 24:
case 32:
{
const void* srcbits;
const BYTE *srcbyte;
BYTE* dstbyte;
int bytes_per_pixel;
srcbits=bmpImage->data+(lines-1)*bmpImage->bytes_per_line;
bytes_per_pixel=(bmpImage->bits_per_pixel==24?3:4);
if (bmpImage->green_mask!=0x00ff00 ||
(bmpImage->red_mask|bmpImage->blue_mask)!=0xff00ff) {
goto notsupported;
} else if (bmpImage->blue_mask==0xff) {
/* ==== rgb 888 or 0888 bmp -> pal 1 dib ==== */
for (h=0; h<lines; h++) {
BYTE dstval;
srcbyte=srcbits;
dstbyte=dstbits;
dstval=0;
for (x=0; x<width; x++) {
dstval|=(X11DRV_DIB_GetNearestIndex
(colors, 2,
srcbyte[2],
srcbyte[1],
srcbyte[0]) << (7-(x&7)) );
srcbyte+=bytes_per_pixel;
if ((x&7)==7) {
*dstbyte++=dstval;
dstval=0;
}
}
if ((width&7)!=0) {
*dstbyte=dstval;
}
srcbits = (const char*)srcbits - bmpImage->bytes_per_line;
dstbits += linebytes;
}
} else {
/* ==== bgr 888 or 0888 bmp -> pal 1 dib ==== */
for (h=0; h<lines; h++) {
BYTE dstval;
srcbyte=srcbits;
dstbyte=dstbits;
dstval=0;
for (x=0; x<width; x++) {
dstval|=(X11DRV_DIB_GetNearestIndex
(colors, 2,
srcbyte[0],
srcbyte[1],
srcbyte[2]) << (7-(x&7)) );
srcbyte+=bytes_per_pixel;
if ((x&7)==7) {
*dstbyte++=dstval;
dstval=0;
}
}
if ((width&7)!=0) {
*dstbyte=dstval;
}
srcbits = (const char*)srcbits - bmpImage->bytes_per_line;
dstbits += linebytes;
}
}
}
break;
default:
notsupported:
{
BYTE* dstbyte;
BYTE neg = 0;
unsigned long white = (1 << bmpImage->bits_per_pixel) - 1;
/* ==== any bmp format -> pal 1 dib ==== */
if ((unsigned)colors[0].rgbRed+colors[0].rgbGreen+colors[0].rgbBlue >=
(unsigned)colors[1].rgbRed+colors[1].rgbGreen+colors[1].rgbBlue )
neg = 1;
WARN("from unknown %d bit bitmap (%lx,%lx,%lx) to 1 bit DIB, "
"%s color mapping\n",
bmpImage->bits_per_pixel, bmpImage->red_mask,
bmpImage->green_mask, bmpImage->blue_mask,
neg?"negative":"direct" );
for (h=lines-1; h>=0; h--) {
BYTE dstval;
dstbyte=dstbits;
dstval=0;
for (x=0; x<width; x++) {
dstval|=((XGetPixel( bmpImage, x, h) >= white) ^ neg) << (7 - (x&7));
if ((x&7)==7) {
*dstbyte++=dstval;
dstval=0;
}
}
if ((width&7)!=0) {
*dstbyte=dstval;
}
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)
{
int h, width;
const BYTE* srcbyte;
DWORD i, x;
if (lines < 0 ) {
lines = -lines;
srcbits = srcbits + linebytes * (lines - 1);
linebytes = -linebytes;
}
if (left & 1) {
left--;
dstwidth++;
}
srcbits += left >> 1;
width = min(srcwidth, dstwidth);
/* ==== pal 4 dib -> any bmp format ==== */
for (h = lines-1; h >= 0; h--) {
srcbyte=srcbits;
for (i = width/2, x = left; i > 0; i--) {
BYTE srcval=*srcbyte++;
XPutPixel( bmpImage, x++, h, colors[srcval >> 4] );
XPutPixel( bmpImage, x++, h, colors[srcval & 0x0f] );
}
if (width & 1)
XPutPixel( bmpImage, x, h, colors[*srcbyte >> 4] );
srcbits += linebytes;
}
}
/***********************************************************************
* 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, width = min(srcwidth, dstwidth);
BYTE *bits;
if (lines < 0 )
{
lines = -lines;
dstbits = dstbits + ( linebytes * (lines-1) );
linebytes = -linebytes;
}
bits = dstbits;
switch (bmpImage->depth) {
case 1:
case 4:
if (X11DRV_DIB_CheckMask(bmpImage->red_mask,bmpImage->green_mask,bmpImage->blue_mask)
&& srccolors) {
/* ==== pal 1 or 4 bmp -> pal 4 dib ==== */
BYTE* dstbyte;
for (h = lines-1; h >= 0; h--) {
BYTE dstval;
dstbyte=dstbits;
dstval=0;
for (x = 0; x < width; x++) {
PALETTEENTRY srcval;
srcval=srccolors[XGetPixel(bmpImage, x, h)];
dstval|=(X11DRV_DIB_GetNearestIndex
(colors, 16,
srcval.peRed,
srcval.peGreen,
srcval.peBlue) << (4-((x&1)<<2)));
if ((x&1)==1) {
*dstbyte++=dstval;
dstval=0;
}
}
if ((width&1)!=0) {
*dstbyte=dstval;
}
dstbits += linebytes;
}
} else {
goto notsupported;
}
break;
case 8:
if (X11DRV_DIB_CheckMask(bmpImage->red_mask,bmpImage->green_mask,bmpImage->blue_mask)
&& srccolors) {
/* ==== pal 8 bmp -> pal 4 dib ==== */
const void* srcbits;
const BYTE *srcpixel;
BYTE* dstbyte;
srcbits=bmpImage->data+(lines-1)*bmpImage->bytes_per_line;
for (h=0; h<lines; h++) {
BYTE dstval;
srcpixel=srcbits;
dstbyte=dstbits;
dstval=0;
for (x=0; x<width; x++) {
PALETTEENTRY srcval;
srcval = srccolors[*srcpixel++];
dstval|=(X11DRV_DIB_GetNearestIndex
(colors, 16,
srcval.peRed,
srcval.peGreen,
srcval.peBlue) << (4*(1-(x&1))) );
if ((x&1)==1) {
*dstbyte++=dstval;
dstval=0;
}
}
if ((width&1)!=0) {
*dstbyte=dstval;
}
srcbits = (const char*)srcbits - bmpImage->bytes_per_line;
dstbits += linebytes;
}
} else {
goto notsupported;
}
break;
case 15:
case 16:
{
const void* srcbits;
const WORD* srcpixel;
BYTE* dstbyte;
srcbits=bmpImage->data+(lines-1)*bmpImage->bytes_per_line;
if (bmpImage->green_mask==0x03e0) {
if (bmpImage->red_mask==0x7c00) {
/* ==== rgb 555 bmp -> pal 4 dib ==== */
for (h=0; h<lines; h++) {
BYTE dstval;
srcpixel=srcbits;
dstbyte=dstbits;
dstval=0;
for (x=0; x<width; x++) {
WORD srcval;
srcval=*srcpixel++;
dstval|=(X11DRV_DIB_GetNearestIndex
(colors, 16,
((srcval >> 7) & 0xf8) | /* r */
((srcval >> 12) & 0x07),
((srcval >> 2) & 0xf8) | /* g */
((srcval >> 7) & 0x07),
((srcval << 3) & 0xf8) | /* b */
((srcval >> 2) & 0x07) ) << ((1-(x&1))<<2) );
if ((x&1)==1) {
*dstbyte++=dstval;
dstval=0;
}
}
if ((width&1)!=0) {
*dstbyte=dstval;
}
srcbits = (const char*)srcbits - bmpImage->bytes_per_line;
dstbits += linebytes;
}
} else if (bmpImage->blue_mask==0x7c00) {
/* ==== bgr 555 bmp -> pal 4 dib ==== */
for (h=0; h<lines; h++) {
WORD dstval;
srcpixel=srcbits;
dstbyte=dstbits;
dstval=0;
for (x=0; x<width; x++) {
WORD srcval;
srcval=*srcpixel++;
dstval|=(X11DRV_DIB_GetNearestIndex
(colors, 16,
((srcval << 3) & 0xf8) | /* r */
((srcval >> 2) & 0x07),
((srcval >> 2) & 0xf8) | /* g */
((srcval >> 7) & 0x07),
((srcval >> 7) & 0xf8) | /* b */
((srcval >> 12) & 0x07) ) << ((1-(x&1))<<2) );
if ((x&1)==1) {
*dstbyte++=dstval;
dstval=0;
}
}
if ((width&1)!=0) {
*dstbyte=dstval;
}
srcbits = (const char*)srcbits - bmpImage->bytes_per_line;
dstbits += linebytes;
}
} else {
goto notsupported;
}
} else if (bmpImage->green_mask==0x07e0) {
if (bmpImage->red_mask==0xf800) {
/* ==== rgb 565 bmp -> pal 4 dib ==== */
for (h=0; h<lines; h++) {
BYTE dstval;
srcpixel=srcbits;
dstbyte=dstbits;
dstval=0;
for (x=0; x<width; x++) {
WORD srcval;
srcval=*srcpixel++;
dstval|=(X11DRV_DIB_GetNearestIndex
(colors, 16,
((srcval >> 8) & 0xf8) | /* r */
((srcval >> 13) & 0x07),
((srcval >> 3) & 0xfc) | /* g */
((srcval >> 9) & 0x03),
((srcval << 3) & 0xf8) | /* b */
((srcval >> 2) & 0x07) ) << ((1-(x&1))<<2) );
if ((x&1)==1) {
*dstbyte++=dstval;
dstval=0;
}
}
if ((width&1)!=0) {
*dstbyte=dstval;
}
srcbits = (const char*)srcbits - bmpImage->bytes_per_line;
dstbits += linebytes;
}
} else if (bmpImage->blue_mask==0xf800) {
/* ==== bgr 565 bmp -> pal 4 dib ==== */
for (h=0; h<lines; h++) {
WORD dstval;
srcpixel=srcbits;
dstbyte=dstbits;
dstval=0;
for (x=0; x<width; x++) {
WORD srcval;
srcval=*srcpixel++;
dstval|=(X11DRV_DIB_GetNearestIndex
(colors, 16,
((srcval << 3) & 0xf8) | /* r */
((srcval >> 2) & 0x07),
((srcval >> 3) & 0xfc) | /* g */
((srcval >> 9) & 0x03),
((srcval >> 8) & 0xf8) | /* b */
((srcval >> 13) & 0x07) ) << ((1-(x&1))<<2) );
if ((x&1)==1) {
*dstbyte++=dstval;
dstval=0;
}
}
if ((width&1)!=0) {
*dstbyte=dstval;
}
srcbits = (const char*)srcbits - bmpImage->bytes_per_line;
dstbits += linebytes;
}
} else {
goto notsupported;
}
} else {
goto notsupported;
}
}
break;
case 24:
if (bmpImage->bits_per_pixel==24) {
const void* srcbits;
const BYTE *srcbyte;
BYTE* dstbyte;
srcbits=bmpImage->data+(lines-1)*bmpImage->bytes_per_line;
if (bmpImage->green_mask!=0x00ff00 ||
(bmpImage->red_mask|bmpImage->blue_mask)!=0xff00ff) {
goto notsupported;
} else if (bmpImage->blue_mask==0xff) {
/* ==== rgb 888 bmp -> pal 4 dib ==== */
for (h=0; h<lines; h++) {
srcbyte=srcbits;
dstbyte=dstbits;
for (x=0; x<width/2; x++) {
/* Do 2 pixels at a time */
*dstbyte++=(X11DRV_DIB_GetNearestIndex
(colors, 16,
srcbyte[2],
srcbyte[1],
srcbyte[0]) << 4) |
X11DRV_DIB_GetNearestIndex
(colors, 16,
srcbyte[5],
srcbyte[4],
srcbyte[3]);
srcbyte+=6;
}
if (width&1) {
/* And then the odd pixel */
*dstbyte++=(X11DRV_DIB_GetNearestIndex
(colors, 16,
srcbyte[2],
srcbyte[1],
srcbyte[0]) << 4);
}
srcbits = (const char*)srcbits - bmpImage->bytes_per_line;
dstbits += linebytes;
}
} else {
/* ==== bgr 888 bmp -> pal 4 dib ==== */
for (h=0; h<lines; h++) {
srcbyte=srcbits;
dstbyte=dstbits;
for (x=0; x<width/2; x++) {
/* Do 2 pixels at a time */
*dstbyte++=(X11DRV_DIB_GetNearestIndex
(colors, 16,
srcbyte[0],
srcbyte[1],
srcbyte[2]) << 4) |
X11DRV_DIB_GetNearestIndex
(colors, 16,
srcbyte[3],
srcbyte[4],
srcbyte[5]);
srcbyte+=6;
}
if (width&1) {
/* And then the odd pixel */
*dstbyte++=(X11DRV_DIB_GetNearestIndex
(colors, 16,
srcbyte[0],
srcbyte[1],
srcbyte[2]) << 4);
}
srcbits = (const char*)srcbits - bmpImage->bytes_per_line;
dstbits += linebytes;
}
}
break;
}
/* Fall through */
case 32:
{
const void* srcbits;
const BYTE *srcbyte;
BYTE* dstbyte;
srcbits=bmpImage->data+(lines-1)*bmpImage->bytes_per_line;
if (bmpImage->green_mask!=0x00ff00 ||
(bmpImage->red_mask|bmpImage->blue_mask)!=0xff00ff) {
goto notsupported;
} else if (bmpImage->blue_mask==0xff) {
/* ==== rgb 0888 bmp -> pal 4 dib ==== */
for (h=0; h<lines; h++) {
srcbyte=srcbits;
dstbyte=dstbits;
for (x=0; x<width/2; x++) {
/* Do 2 pixels at a time */
*dstbyte++=(X11DRV_DIB_GetNearestIndex
(colors, 16,
srcbyte[2],
srcbyte[1],
srcbyte[0]) << 4) |
X11DRV_DIB_GetNearestIndex
(colors, 16,
srcbyte[6],
srcbyte[5],
srcbyte[4]);
srcbyte+=8;
}
if (width&1) {
/* And then the odd pixel */
*dstbyte++=(X11DRV_DIB_GetNearestIndex
(colors, 16,
srcbyte[2],
srcbyte[1],
srcbyte[0]) << 4);
}
srcbits = (const char*)srcbits - bmpImage->bytes_per_line;
dstbits += linebytes;
}
} else {
/* ==== bgr 0888 bmp -> pal 4 dib ==== */
for (h=0; h<lines; h++) {
srcbyte=srcbits;
dstbyte=dstbits;
for (x=0; x<width/2; x++) {
/* Do 2 pixels at a time */
*dstbyte++=(X11DRV_DIB_GetNearestIndex
(colors, 16,
srcbyte[0],
srcbyte[1],
srcbyte[2]) << 4) |
X11DRV_DIB_GetNearestIndex
(colors, 16,
srcbyte[4],
srcbyte[5],
srcbyte[6]);
srcbyte+=8;
}
if (width&1) {
/* And then the odd pixel */
*dstbyte++=(X11DRV_DIB_GetNearestIndex
(colors, 16,
srcbyte[0],
srcbyte[1],
srcbyte[2]) << 4);
}
srcbits = (const char*)srcbits - bmpImage->bytes_per_line;
dstbits += linebytes;
}
}
}
break;
default:
notsupported:
{
BYTE* dstbyte;
/* ==== any bmp format -> pal 4 dib ==== */
WARN("from unknown %d bit bitmap (%lx,%lx,%lx) to 4 bit DIB\n",
bmpImage->bits_per_pixel, bmpImage->red_mask,
bmpImage->green_mask, bmpImage->blue_mask );
for (h=lines-1; h>=0; h--) {
dstbyte=dstbits;
for (x=0; x<(width & ~1); x+=2) {
*dstbyte++=(X11DRV_DIB_MapColor((int*)colors, 16, XGetPixel(bmpImage, x, h), 0) << 4) |
X11DRV_DIB_MapColor((int*)colors, 16, XGetPixel(bmpImage, x+1, h), 0);
}
if (width & 1) {
*dstbyte=(X11DRV_DIB_MapColor((int *)colors, 16, XGetPixel(bmpImage, x, h), 0) << 4);
}
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 srcwidth, DWORD dstwidth,
int left, int *colors,
XImage *bmpImage )
{
unsigned int x = 0, width = min(srcwidth, dstwidth);
int y = lines - 1, c, length;
const BYTE *begin = bits;
while (y >= 0)
{
length = *bits++;
if (length) { /* encoded */
c = *bits++;
while (length--) {
if (x >= (left + width)) break;
if( x >= left) XPutPixel(bmpImage, x, y, colors[c >> 4]);
x++;
if (!length--) break;
if (x >= (left + width)) break;
if( x >= left) XPutPixel(bmpImage, x, y, colors[c & 0xf]);
x++;
}
} 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 >= left && x < (left + width))
XPutPixel(bmpImage, x, y, colors[c >> 4]);
x++;
if (!length--) break;
if (x >= left && x < (left + width))
XPutPixel(bmpImage, x, y, colors[c & 0xf]);
x++;
}
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, width = min(srcwidth, dstwidth);
const BYTE* srcbyte;
BYTE* dstbits;
if (lines < 0 )
{
lines = -lines;
srcbits = srcbits + linebytes * (lines-1);
linebytes = -linebytes;
}
srcbits += left;
srcbyte = srcbits;
switch (bmpImage->depth) {
case 15:
case 16:
/* Some X servers might have 32 bit/ 16bit deep pixel */
if (lines && width && (bmpImage->bits_per_pixel == 16) &&
(ImageByteOrder(gdi_display)==LSBFirst) )
{
/* ==== pal 8 dib -> rgb or bgr 555 or 565 bmp ==== */
dstbits=(BYTE*)bmpImage->data+left*2+(lines-1)*bmpImage->bytes_per_line;
for (h = lines ; h--; ) {
#if defined(__i386__) && defined(__GNUC__)
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" (srcbyte), "=D" (_cl1), "=c" (_cl2)
:"S" (srcbyte),
"D" (dstbits),
"c" (width),
"d" (colors)
:"eax", "cc", "memory"
);
#else
DWORD* dstpixel=(DWORD*)dstbits;
for (x=0; x<width/2; x++) {
/* Do 2 pixels at a time */
*dstpixel++=(colors[srcbyte[1]] << 16) | colors[srcbyte[0]];
srcbyte+=2;
}
if (width&1) {
/* And then the odd pixel */
*((WORD*)dstpixel)=colors[srcbyte[0]];
}
#endif
srcbyte = (srcbits += linebytes);
dstbits -= bmpImage->bytes_per_line;
}
return;
}
break;
case 24:
case 32:
if (lines && width && (bmpImage->bits_per_pixel == 32) &&
(ImageByteOrder(gdi_display)==LSBFirst) )
{
dstbits=(BYTE*)bmpImage->data+left*4+(lines-1)*bmpImage->bytes_per_line;
/* ==== pal 8 dib -> rgb or bgr 0888 bmp ==== */
for (h = lines ; h--; ) {
#if defined(__i386__) && defined(__GNUC__)
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" (srcbyte), "=D" (_cl1), "=c" (_cl2)
:"S" (srcbyte),
"D" (dstbits),
"c" (width),
"d" (colors)
:"eax", "cc", "memory"
);
#else
DWORD* dstpixel=(DWORD*)dstbits;
for (x=0; x<width; x++) {
*dstpixel++=colors[*srcbyte++];
}
#endif
srcbyte = (srcbits += linebytes);
dstbits -= bmpImage->bytes_per_line;
}
return;
}
break;
default:
break; /* use slow generic case below */
}
/* ==== pal 8 dib -> any bmp format ==== */
for (h=lines-1; h>=0; h--) {
for (x=left; x<width+left; x++) {
XPutPixel(bmpImage, x, h, colors[*srcbyte++]);
}
srcbyte = (srcbits += linebytes);
}
}
/***********************************************************************
* 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, width = min(srcwidth, dstwidth);
BYTE* dstbyte;
if (lines < 0 )
{
lines = -lines;
dstbits = dstbits + ( linebytes * (lines-1) );
linebytes = -linebytes;
}
/*
* 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 it for GetDIBits calls.
* (In some cases, in an updateDIBSection, the returned colors are bad too)
*/
if (!srccolors) goto updatesection;
switch (bmpImage->depth) {
case 1:
case 4:
if (X11DRV_DIB_CheckMask(bmpImage->red_mask,bmpImage->green_mask,bmpImage->blue_mask)
&& srccolors) {
/* ==== pal 1 bmp -> pal 8 dib ==== */
/* ==== pal 4 bmp -> pal 8 dib ==== */
for (h=lines-1; h>=0; h--) {
dstbyte=dstbits;
for (x=0; x<width; x++) {
PALETTEENTRY srcval;
srcval=srccolors[XGetPixel(bmpImage, x, h)];
*dstbyte++=X11DRV_DIB_GetNearestIndex(colors, 256,
srcval.peRed,
srcval.peGreen,
srcval.peBlue);
}
dstbits += linebytes;
}
} else {
goto notsupported;
}
break;
case 8:
if (X11DRV_DIB_CheckMask(bmpImage->red_mask,bmpImage->green_mask,bmpImage->blue_mask)
&& srccolors) {
/* ==== pal 8 bmp -> pal 8 dib ==== */
const void* srcbits;
const BYTE* srcpixel;
srcbits=bmpImage->data+(lines-1)*bmpImage->bytes_per_line;
for (h=0; h<lines; h++) {
srcpixel=srcbits;
dstbyte=dstbits;
for (x = 0; x < width; x++) {
PALETTEENTRY srcval;
srcval=srccolors[*srcpixel++];
*dstbyte++=X11DRV_DIB_GetNearestIndex(colors, 256,
srcval.peRed,
srcval.peGreen,
srcval.peBlue);
}
srcbits = (const char*)srcbits - bmpImage->bytes_per_line;
dstbits += linebytes;
}
} else {
goto notsupported;
}
break;
case 15:
case 16:
{
const void* srcbits;
const WORD* srcpixel;
BYTE* dstbyte;
srcbits=bmpImage->data+(lines-1)*bmpImage->bytes_per_line;
if (bmpImage->green_mask==0x03e0) {
if (bmpImage->red_mask==0x7c00) {
/* ==== rgb 555 bmp -> pal 8 dib ==== */
for (h=0; h<lines; h++) {
srcpixel=srcbits;
dstbyte=dstbits;
for (x=0; x<width; x++) {
WORD srcval;
srcval=*srcpixel++;
*dstbyte++=X11DRV_DIB_GetNearestIndex
(colors, 256,
((srcval >> 7) & 0xf8) | /* r */
((srcval >> 12) & 0x07),
((srcval >> 2) & 0xf8) | /* g */
((srcval >> 7) & 0x07),
((srcval << 3) & 0xf8) | /* b */
((srcval >> 2) & 0x07) );
}
srcbits = (const char*)srcbits - bmpImage->bytes_per_line;
dstbits += linebytes;
}
} else if (bmpImage->blue_mask==0x7c00) {
/* ==== bgr 555 bmp -> pal 8 dib ==== */
for (h=0; h<lines; h++) {
srcpixel=srcbits;
dstbyte=dstbits;
for (x=0; x<width; x++) {
WORD srcval;
srcval=*srcpixel++;
*dstbyte++=X11DRV_DIB_GetNearestIndex
(colors, 256,
((srcval << 3) & 0xf8) | /* r */
((srcval >> 2) & 0x07),
((srcval >> 2) & 0xf8) | /* g */
((srcval >> 7) & 0x07),
((srcval >> 7) & 0xf8) | /* b */
((srcval >> 12) & 0x07) );
}
srcbits = (const char*)srcbits - bmpImage->bytes_per_line;
dstbits += linebytes;
}
} else {
goto notsupported;
}
} else if (bmpImage->green_mask==0x07e0) {
if (bmpImage->red_mask==0xf800) {
/* ==== rgb 565 bmp -> pal 8 dib ==== */
for (h=0; h<lines; h++) {
srcpixel=srcbits;
dstbyte=dstbits;
for (x=0; x<width; x++) {
WORD srcval;
srcval=*srcpixel++;
*dstbyte++=X11DRV_DIB_GetNearestIndex
(colors, 256,
((srcval >> 8) & 0xf8) | /* r */
((srcval >> 13) & 0x07),
((srcval >> 3) & 0xfc) | /* g */
((srcval >> 9) & 0x03),
((srcval << 3) & 0xf8) | /* b */
((srcval >> 2) & 0x07) );
}
srcbits = (const char*)srcbits - bmpImage->bytes_per_line;
dstbits += linebytes;
}
} else if (bmpImage->blue_mask==0xf800) {
/* ==== bgr 565 bmp -> pal 8 dib ==== */
for (h=0; h<lines; h++) {
srcpixel=srcbits;
dstbyte=dstbits;
for (x=0; x<width; x++) {
WORD srcval;
srcval=*srcpixel++;
*dstbyte++=X11DRV_DIB_GetNearestIndex
(colors, 256,
((srcval << 3) & 0xf8) | /* r */
((srcval >> 2) & 0x07),
((srcval >> 3) & 0xfc) | /* g */
((srcval >> 9) & 0x03),
((srcval >> 8) & 0xf8) | /* b */
((srcval >> 13) & 0x07) );
}
srcbits = (const char*)srcbits - bmpImage->bytes_per_line;
dstbits += linebytes;
}
} else {
goto notsupported;
}
} else {
goto notsupported;
}
}
break;
case 24:
case 32:
{
const void* srcbits;
const BYTE *srcbyte;
BYTE* dstbyte;
int bytes_per_pixel;
srcbits=bmpImage->data+(lines-1)*bmpImage->bytes_per_line;
bytes_per_pixel=(bmpImage->bits_per_pixel==24?3:4);
if (bmpImage->green_mask!=0x00ff00 ||
(bmpImage->red_mask|bmpImage->blue_mask)!=0xff00ff) {
goto notsupported;
} else if (bmpImage->blue_mask==0xff) {
/* ==== rgb 888 or 0888 bmp -> pal 8 dib ==== */
for (h=0; h<lines; h++) {
srcbyte=srcbits;
dstbyte=dstbits;
for (x=0; x<width; x++) {
*dstbyte++=X11DRV_DIB_GetNearestIndex
(colors, 256,
srcbyte[2],
srcbyte[1],
srcbyte[0]);
srcbyte+=bytes_per_pixel;
}
srcbits = (const char*)srcbits - bmpImage->bytes_per_line;
dstbits += linebytes;
}
} else {
/* ==== bgr 888 or 0888 bmp -> pal 8 dib ==== */
for (h=0; h<lines; h++) {
srcbyte=srcbits;
dstbyte=dstbits;
for (x=0; x<width; x++) {
*dstbyte++=X11DRV_DIB_GetNearestIndex
(colors, 256,
srcbyte[0],
srcbyte[1],
srcbyte[2]);
srcbyte+=bytes_per_pixel;
}
srcbits = (const char*)srcbits - bmpImage->bytes_per_line;
dstbits += linebytes;
}
}
}
break;
default:
notsupported:
WARN("from unknown %d bit bitmap (%lx,%lx,%lx) to 8 bit DIB\n",
bmpImage->depth, bmpImage->red_mask,
bmpImage->green_mask, bmpImage->blue_mask );
updatesection:
/* ==== any bmp format -> pal 8 dib ==== */
for (h=lines-1; h>=0; h--) {
dstbyte=dstbits;
for (x=0; x<width; x++) {
*dstbyte=X11DRV_DIB_MapColor
((int*)colors, 256,
XGetPixel(bmpImage, x, h), *dstbyte);
dstbyte++;
}
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 srcwidth, DWORD dstwidth,
int left, int *colors,
XImage *bmpImage )
{
unsigned int x; /* X-position 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 < (left + dstwidth)) {
if( x >= left) XPutPixel(bmpImage, x, y, color);
x++;
}
}
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 >= (left + dstwidth))
{
pIn += length;
break;
}
if( x >= left) XPutPixel(bmpImage, x, y, color);
x++;
}
/*
* 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,
X11DRV_PDEVICE *physDev, DWORD rSrc, DWORD gSrc, DWORD bSrc,
XImage *bmpImage, DWORD linebytes )
{
DWORD x;
int h, width = min(srcwidth, dstwidth);
const dib_conversions *convs = (bmpImage->byte_order == LSBFirst) ? &dib_normal : &dib_dst_byteswap;
if (lines < 0 )
{
lines = -lines;
srcbits = srcbits + ( linebytes * (lines-1));
linebytes = -linebytes;
}
switch (bmpImage->depth)
{
case 15:
case 16:
{
char* dstbits;
srcbits=srcbits+left*2;
dstbits=bmpImage->data+left*2+(lines-1)*bmpImage->bytes_per_line;
if (bmpImage->green_mask==0x03e0) {
if (gSrc==bmpImage->green_mask) {
if (rSrc==bmpImage->red_mask) {
/* ==== rgb 555 dib -> rgb 555 bmp ==== */
/* ==== bgr 555 dib -> bgr 555 bmp ==== */
convs->Convert_5x5_asis
(width,lines,
srcbits,linebytes,
dstbits,-bmpImage->bytes_per_line);
} else if (rSrc==bmpImage->blue_mask) {
/* ==== rgb 555 dib -> bgr 555 bmp ==== */
/* ==== bgr 555 dib -> rgb 555 bmp ==== */
convs->Convert_555_reverse
(width,lines,
srcbits,linebytes,
dstbits,-bmpImage->bytes_per_line);
}
} else {
if (rSrc==bmpImage->red_mask || bSrc==bmpImage->blue_mask) {
/* ==== rgb 565 dib -> rgb 555 bmp ==== */
/* ==== bgr 565 dib -> bgr 555 bmp ==== */
convs->Convert_565_to_555_asis
(width,lines,
srcbits,linebytes,
dstbits,-bmpImage->bytes_per_line);
} else {
/* ==== rgb 565 dib -> bgr 555 bmp ==== */
/* ==== bgr 565 dib -> rgb 555 bmp ==== */
convs->Convert_565_to_555_reverse
(width,lines,
srcbits,linebytes,
dstbits,-bmpImage->bytes_per_line);
}
}
} else if (bmpImage->green_mask==0x07e0) {
if (gSrc==bmpImage->green_mask) {
if (rSrc==bmpImage->red_mask) {
/* ==== rgb 565 dib -> rgb 565 bmp ==== */
/* ==== bgr 565 dib -> bgr 565 bmp ==== */
convs->Convert_5x5_asis
(width,lines,
srcbits,linebytes,
dstbits,-bmpImage->bytes_per_line);
} else {
/* ==== rgb 565 dib -> bgr 565 bmp ==== */
/* ==== bgr 565 dib -> rgb 565 bmp ==== */
convs->Convert_565_reverse
(width,lines,
srcbits,linebytes,
dstbits,-bmpImage->bytes_per_line);
}
} else {
if (rSrc==bmpImage->red_mask || bSrc==bmpImage->blue_mask) {
/* ==== rgb 555 dib -> rgb 565 bmp ==== */
/* ==== bgr 555 dib -> bgr 565 bmp ==== */
convs->Convert_555_to_565_asis
(width,lines,
srcbits,linebytes,
dstbits,-bmpImage->bytes_per_line);
} else {
/* ==== rgb 555 dib -> bgr 565 bmp ==== */
/* ==== bgr 555 dib -> rgb 565 bmp ==== */
convs->Convert_555_to_565_reverse
(width,lines,
srcbits,linebytes,
dstbits,-bmpImage->bytes_per_line);
}
}
} else {
goto notsupported;
}
}
break;
case 24:
if (bmpImage->bits_per_pixel==24) {
char* dstbits;
srcbits=srcbits+left*2;
dstbits=bmpImage->data+left*3+(lines-1)*bmpImage->bytes_per_line;
if (bmpImage->green_mask!=0x00ff00 ||
(bmpImage->red_mask|bmpImage->blue_mask)!=0xff00ff) {
goto notsupported;
} else if ((rSrc==0x1f && bmpImage->red_mask==0xff) ||
(bSrc==0x1f && bmpImage->blue_mask==0xff)) {
if (gSrc==0x03e0) {
/* ==== rgb 555 dib -> rgb 888 bmp ==== */
/* ==== bgr 555 dib -> bgr 888 bmp ==== */
convs->Convert_555_to_888_asis
(width,lines,
srcbits,linebytes,
dstbits,-bmpImage->bytes_per_line);
} else {
/* ==== rgb 565 dib -> rgb 888 bmp ==== */
/* ==== bgr 565 dib -> bgr 888 bmp ==== */
convs->Convert_565_to_888_asis
(width,lines,
srcbits,linebytes,
dstbits,-bmpImage->bytes_per_line);
}
} else {
if (gSrc==0x03e0) {
/* ==== rgb 555 dib -> bgr 888 bmp ==== */
/* ==== bgr 555 dib -> rgb 888 bmp ==== */
convs->Convert_555_to_888_reverse
(width,lines,
srcbits,linebytes,
dstbits,-bmpImage->bytes_per_line);
} else {
/* ==== rgb 565 dib -> bgr 888 bmp ==== */
/* ==== bgr 565 dib -> rgb 888 bmp ==== */
convs->Convert_565_to_888_reverse
(width,lines,
srcbits,linebytes,
dstbits,-bmpImage->bytes_per_line);
}
}
break;
}
/* Fall through */
case 32:
{
char* dstbits;
srcbits=srcbits+left*2;
dstbits=bmpImage->data+left*4+(lines-1)*bmpImage->bytes_per_line;
if (bmpImage->green_mask!=0x00ff00 ||
(bmpImage->red_mask|bmpImage->blue_mask)!=0xff00ff) {
goto notsupported;
} else if ((rSrc==0x1f && bmpImage->red_mask==0xff) ||
(bSrc==0x1f && bmpImage->blue_mask==0xff)) {
if (gSrc==0x03e0) {
/* ==== rgb 555 dib -> rgb 0888 bmp ==== */
/* ==== bgr 555 dib -> bgr 0888 bmp ==== */
convs->Convert_555_to_0888_asis
(width,lines,
srcbits,linebytes,
dstbits,-bmpImage->bytes_per_line);
} else {
/* ==== rgb 565 dib -> rgb 0888 bmp ==== */
/* ==== bgr 565 dib -> bgr 0888 bmp ==== */
convs->Convert_565_to_0888_asis
(width,lines,
srcbits,linebytes,
dstbits,-bmpImage->bytes_per_line);
}
} else {
if (gSrc==0x03e0) {
/* ==== rgb 555 dib -> bgr 0888 bmp ==== */
/* ==== bgr 555 dib -> rgb 0888 bmp ==== */
convs->Convert_555_to_0888_reverse
(width,lines,
srcbits,linebytes,
dstbits,-bmpImage->bytes_per_line);
} else {
/* ==== rgb 565 dib -> bgr 0888 bmp ==== */
/* ==== bgr 565 dib -> rgb 0888 bmp ==== */
convs->Convert_565_to_0888_reverse
(width,lines,
srcbits,linebytes,
dstbits,-bmpImage->bytes_per_line);
}
}
}
break;
default:
notsupported:
WARN("from 16 bit DIB (%x,%x,%x) to unknown %d bit bitmap (%lx,%lx,%lx)\n",
rSrc, gSrc, bSrc, bmpImage->bits_per_pixel, bmpImage->red_mask,
bmpImage->green_mask, bmpImage->blue_mask );
/* fall through */
case 1:
case 4:
case 8:
{
/* ==== rgb or bgr 555 or 565 dib -> pal 1, 4 or 8 ==== */
const WORD* srcpixel;
int rShift1,gShift1,bShift1;
int rShift2,gShift2,bShift2;
BYTE gMask1,gMask2;
/* Set color scaling values */
rShift1=16+X11DRV_DIB_MaskToShift(rSrc)-3;
gShift1=16+X11DRV_DIB_MaskToShift(gSrc)-3;
bShift1=16+X11DRV_DIB_MaskToShift(bSrc)-3;
rShift2=rShift1+5;
gShift2=gShift1+5;
bShift2=bShift1+5;
if (gSrc==0x03e0) {
/* Green has 5 bits, like the others */
gMask1=0xf8;
gMask2=0x07;
} else {
/* Green has 6 bits, not 5. Compensate. */
gShift1++;
gShift2+=2;
gMask1=0xfc;
gMask2=0x03;
}
srcbits+=2*left;
/* We could split it into four separate cases to optimize
* but it is probably not worth it.
*/
for (h=lines-1; h>=0; h--) {
srcpixel=(const WORD*)srcbits;
for (x=left; x<width+left; x++) {
DWORD srcval;
BYTE red,green,blue;
srcval=*srcpixel++ << 16;
red= ((srcval >> rShift1) & 0xf8) |
((srcval >> rShift2) & 0x07);
green=((srcval >> gShift1) & gMask1) |
((srcval >> gShift2) & gMask2);
blue= ((srcval >> bShift1) & 0xf8) |
((srcval >> bShift2) & 0x07);
XPutPixel(bmpImage, x, h,
X11DRV_PALETTE_ToPhysical
(physDev, RGB(red,green,blue)));
}
srcbits += linebytes;
}
}
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, width = min(srcwidth, dstwidth);
const dib_conversions *convs = (bmpImage->byte_order == LSBFirst) ? &dib_normal : &dib_src_byteswap;
DWORD linebytes = dibpitch;
if (lines < 0 )
{
lines = -lines;
dstbits = dstbits + ( linebytes * (lines-1));
linebytes = -linebytes;
}
switch (bmpImage->depth)
{
case 15:
case 16:
{
const char* srcbits;
srcbits=bmpImage->data+(lines-1)*bmpImage->bytes_per_line;
if (bmpImage->green_mask==0x03e0) {
if (gDst==bmpImage->green_mask) {
if (rDst==bmpImage->red_mask) {
/* ==== rgb 555 bmp -> rgb 555 dib ==== */
/* ==== bgr 555 bmp -> bgr 555 dib ==== */
convs->Convert_5x5_asis
(width,lines,
srcbits,-bmpImage->bytes_per_line,
dstbits,linebytes);
} else {
/* ==== rgb 555 bmp -> bgr 555 dib ==== */
/* ==== bgr 555 bmp -> rgb 555 dib ==== */
convs->Convert_555_reverse
(width,lines,
srcbits,-bmpImage->bytes_per_line,
dstbits,linebytes);
}
} else {
if (rDst==bmpImage->red_mask || bDst==bmpImage->blue_mask) {
/* ==== rgb 555 bmp -> rgb 565 dib ==== */
/* ==== bgr 555 bmp -> bgr 565 dib ==== */
convs->Convert_555_to_565_asis
(width,lines,
srcbits,-bmpImage->bytes_per_line,
dstbits,linebytes);
} else {
/* ==== rgb 555 bmp -> bgr 565 dib ==== */
/* ==== bgr 555 bmp -> rgb 565 dib ==== */
convs->Convert_555_to_565_reverse
(width,lines,
srcbits,-bmpImage->bytes_per_line,
dstbits,linebytes);
}
}
} else if (bmpImage->green_mask==0x07e0) {
if (gDst==bmpImage->green_mask) {
if (rDst == bmpImage->red_mask) {
/* ==== rgb 565 bmp -> rgb 565 dib ==== */
/* ==== bgr 565 bmp -> bgr 565 dib ==== */
convs->Convert_5x5_asis
(width,lines,
srcbits,-bmpImage->bytes_per_line,
dstbits,linebytes);
} else {
/* ==== rgb 565 bmp -> bgr 565 dib ==== */
/* ==== bgr 565 bmp -> rgb 565 dib ==== */
convs->Convert_565_reverse
(width,lines,
srcbits,-bmpImage->bytes_per_line,
dstbits,linebytes);
}
} else {
if (rDst==bmpImage->red_mask || bDst==bmpImage->blue_mask) {
/* ==== rgb 565 bmp -> rgb 555 dib ==== */
/* ==== bgr 565 bmp -> bgr 555 dib ==== */
convs->Convert_565_to_555_asis
(width,lines,
srcbits,-bmpImage->bytes_per_line,
dstbits,linebytes);
} else {
/* ==== rgb 565 bmp -> bgr 555 dib ==== */
/* ==== bgr 565 bmp -> rgb 555 dib ==== */
convs->Convert_565_to_555_reverse
(width,lines,
srcbits,-bmpImage->bytes_per_line,
dstbits,linebytes);
}
}
} else {
goto notsupported;
}
}
break;
case 24:
if (bmpImage->bits_per_pixel == 24) {
const char* srcbits;
srcbits=bmpImage->data+(lines-1)*bmpImage->bytes_per_line;
if (bmpImage->green_mask!=0x00ff00 ||
(bmpImage->red_mask|bmpImage->blue_mask)!=0xff00ff) {
goto notsupported;
} else if ((rDst==0x1f && bmpImage->red_mask==0xff) ||
(bDst==0x1f && bmpImage->blue_mask==0xff)) {
if (gDst==0x03e0) {
/* ==== rgb 888 bmp -> rgb 555 dib ==== */
/* ==== bgr 888 bmp -> bgr 555 dib ==== */
convs->Convert_888_to_555_asis
(width,lines,
srcbits,-bmpImage->bytes_per_line,
dstbits,linebytes);
} else {
/* ==== rgb 888 bmp -> rgb 565 dib ==== */
/* ==== rgb 888 bmp -> rgb 565 dib ==== */
convs->Convert_888_to_565_asis
(width,lines,
srcbits,-bmpImage->bytes_per_line,
dstbits,linebytes);
}
} else {
if (gDst==0x03e0) {
/* ==== rgb 888 bmp -> bgr 555 dib ==== */
/* ==== bgr 888 bmp -> rgb 555 dib ==== */
convs->Convert_888_to_555_reverse
(width,lines,
srcbits,-bmpImage->bytes_per_line,
dstbits,linebytes);
} else {
/* ==== rgb 888 bmp -> bgr 565 dib ==== */
/* ==== bgr 888 bmp -> rgb 565 dib ==== */
convs->Convert_888_to_565_reverse
(width,lines,
srcbits,-bmpImage->bytes_per_line,
dstbits,linebytes);
}
}
break;
}
/* Fall through */
case 32:
{
const char* srcbits;
srcbits=bmpImage->data+(lines-1)*bmpImage->bytes_per_line;
if (bmpImage->green_mask!=0x00ff00 ||
(bmpImage->red_mask|bmpImage->blue_mask)!=0xff00ff) {
goto notsupported;
} else if ((rDst==0x1f && bmpImage->red_mask==0xff) ||
(bDst==0x1f && bmpImage->blue_mask==0xff)) {
if (gDst==0x03e0) {
/* ==== rgb 0888 bmp -> rgb 555 dib ==== */
/* ==== bgr 0888 bmp -> bgr 555 dib ==== */
convs->Convert_0888_to_555_asis
(width,lines,
srcbits,-bmpImage->bytes_per_line,
dstbits,linebytes);
} else {
/* ==== rgb 0888 bmp -> rgb 565 dib ==== */
/* ==== bgr 0888 bmp -> bgr 565 dib ==== */
convs->Convert_0888_to_565_asis
(width,lines,
srcbits,-bmpImage->bytes_per_line,
dstbits,linebytes);
}
} else {
if (gDst==0x03e0) {
/* ==== rgb 0888 bmp -> bgr 555 dib ==== */
/* ==== bgr 0888 bmp -> rgb 555 dib ==== */
convs->Convert_0888_to_555_reverse
(width,lines,
srcbits,-bmpImage->bytes_per_line,
dstbits,linebytes);
} else {
/* ==== rgb 0888 bmp -> bgr 565 dib ==== */
/* ==== bgr 0888 bmp -> rgb 565 dib ==== */
convs->Convert_0888_to_565_reverse
(width,lines,
srcbits,-bmpImage->bytes_per_line,
dstbits,linebytes);
}
}
}
break;
case 1:
case 4:
if (X11DRV_DIB_CheckMask(bmpImage->red_mask,bmpImage->green_mask,bmpImage->blue_mask)
&& srccolors) {
/* ==== pal 1 or 4 bmp -> rgb or bgr 555 or 565 dib ==== */
int rShift,gShift,bShift;
WORD* dstpixel;
/* Shift everything 16 bits left so that all shifts are >0,
* even for BGR DIBs. Then a single >> 16 will bring everything
* back into place.
*/
rShift=16+X11DRV_DIB_MaskToShift(rDst)-3;
gShift=16+X11DRV_DIB_MaskToShift(gDst)-3;
bShift=16+X11DRV_DIB_MaskToShift(bDst)-3;
if (gDst==0x07e0) {
/* 6 bits for the green */
gShift++;
}
rDst=rDst << 16;
gDst=gDst << 16;
bDst=bDst << 16;
for (h = lines - 1; h >= 0; h--) {
dstpixel=(LPWORD)dstbits;
for (x = 0; x < width; x++) {
PALETTEENTRY srcval;
DWORD dstval;
srcval=srccolors[XGetPixel(bmpImage, x, h)];
dstval=((srcval.peRed << rShift) & rDst) |
((srcval.peGreen << gShift) & gDst) |
((srcval.peBlue << bShift) & bDst);
*dstpixel++=dstval >> 16;
}
dstbits += linebytes;
}
} else {
goto notsupported;
}
break;
case 8:
if (X11DRV_DIB_CheckMask(bmpImage->red_mask,bmpImage->green_mask,bmpImage->blue_mask)
&& srccolors) {
/* ==== pal 8 bmp -> rgb or bgr 555 or 565 dib ==== */
int rShift,gShift,bShift;
const BYTE* srcbits;
const BYTE* srcpixel;
WORD* dstpixel;
/* Shift everything 16 bits left so that all shifts are >0,
* even for BGR DIBs. Then a single >> 16 will bring everything
* back into place.
*/
rShift=16+X11DRV_DIB_MaskToShift(rDst)-3;
gShift=16+X11DRV_DIB_MaskToShift(gDst)-3;
bShift=16+X11DRV_DIB_MaskToShift(bDst)-3;
if (gDst==0x07e0) {
/* 6 bits for the green */
gShift++;
}
rDst=rDst << 16;
gDst=gDst << 16;
bDst=bDst << 16;
srcbits=(BYTE*)bmpImage->data+(lines-1)*bmpImage->bytes_per_line;
for (h=0; h<lines; h++) {
srcpixel=srcbits;
dstpixel=(LPWORD)dstbits;
for (x = 0; x < width; x++) {
PALETTEENTRY srcval;
DWORD dstval;
srcval=srccolors[*srcpixel++];
dstval=((srcval.peRed << rShift) & rDst) |
((srcval.peGreen << gShift) & gDst) |
((srcval.peBlue << bShift) & bDst);
*dstpixel++=dstval >> 16;
}
srcbits -= bmpImage->bytes_per_line;
dstbits += linebytes;
}
} else {
goto notsupported;
}
break;
default:
notsupported:
{
/* ==== any bmp format -> rgb or bgr 555 or 565 dib ==== */
int rShift,gShift,bShift;
WORD* dstpixel;
WARN("from unknown %d bit bitmap (%lx,%lx,%lx) to 16 bit DIB (%x,%x,%x)\n",
bmpImage->depth, bmpImage->red_mask,
bmpImage->green_mask, bmpImage->blue_mask,
rDst, gDst, bDst);
/* Shift everything 16 bits left so that all shifts are >0,
* even for BGR DIBs. Then a single >> 16 will bring everything
* back into place.
*/
rShift=16+X11DRV_DIB_MaskToShift(rDst)-3;
gShift=16+X11DRV_DIB_MaskToShift(gDst)-3;
bShift=16+X11DRV_DIB_MaskToShift(bDst)-3;
if (gDst==0x07e0) {
/* 6 bits for the green */
gShift++;
}
rDst=rDst << 16;
gDst=gDst << 16;
bDst=bDst << 16;
for (h = lines - 1; h >= 0; h--) {
dstpixel=(LPWORD)dstbits;
for (x = 0; x < width; x++) {
COLORREF srcval;
DWORD dstval;
srcval=X11DRV_PALETTE_ToLogical(XGetPixel(bmpImage, x, h));
dstval=((GetRValue(srcval) << rShift) & rDst) |
((GetGValue(srcval) << gShift) & gDst) |
((GetBValue(srcval) << bShift) & bDst);
*dstpixel++=dstval >> 16;
}
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,
X11DRV_PDEVICE *physDev,
DWORD rSrc, DWORD gSrc, DWORD bSrc,
XImage *bmpImage, DWORD linebytes )
{
DWORD x;
int h, width = min(srcwidth, dstwidth);
const dib_conversions *convs = (bmpImage->byte_order == LSBFirst) ? &dib_normal : &dib_dst_byteswap;
if (lines < 0 )
{
lines = -lines;
srcbits = srcbits + linebytes * (lines - 1);
linebytes = -linebytes;
}
switch (bmpImage->depth)
{
case 24:
if (bmpImage->bits_per_pixel==24) {
char* dstbits;
srcbits=srcbits+left*3;
dstbits=bmpImage->data+left*3+(lines-1)*bmpImage->bytes_per_line;
if (bmpImage->green_mask!=0x00ff00 ||
(bmpImage->red_mask|bmpImage->blue_mask)!=0xff00ff) {
goto notsupported;
} else if (rSrc==bmpImage->red_mask) {
/* ==== rgb 888 dib -> rgb 888 bmp ==== */
/* ==== bgr 888 dib -> bgr 888 bmp ==== */
convs->Convert_888_asis
(width,lines,
srcbits,linebytes,
dstbits,-bmpImage->bytes_per_line);
} else {
/* ==== rgb 888 dib -> bgr 888 bmp ==== */
/* ==== bgr 888 dib -> rgb 888 bmp ==== */
convs->Convert_888_reverse
(width,lines,
srcbits,linebytes,
dstbits,-bmpImage->bytes_per_line);
}
break;
}
/* fall through */
case 32:
{
char* dstbits;
srcbits=srcbits+left*3;
dstbits=bmpImage->data+left*4+(lines-1)*bmpImage->bytes_per_line;
if (bmpImage->green_mask!=0x00ff00 ||
(bmpImage->red_mask|bmpImage->blue_mask)!=0xff00ff) {
goto notsupported;
} else if (rSrc==bmpImage->red_mask) {
/* ==== rgb 888 dib -> rgb 0888 bmp ==== */
/* ==== bgr 888 dib -> bgr 0888 bmp ==== */
convs->Convert_888_to_0888_asis
(width,lines,
srcbits,linebytes,
dstbits,-bmpImage->bytes_per_line);
} else {
/* ==== rgb 888 dib -> bgr 0888 bmp ==== */
/* ==== bgr 888 dib -> rgb 0888 bmp ==== */
convs->Convert_888_to_0888_reverse
(width,lines,
srcbits,linebytes,
dstbits,-bmpImage->bytes_per_line);
}
break;
}
case 15:
case 16:
{
char* dstbits;
srcbits=srcbits+left*3;
dstbits=bmpImage->data+left*2+(lines-1)*bmpImage->bytes_per_line;
if (bmpImage->green_mask==0x03e0) {
if ((rSrc==0xff0000 && bmpImage->red_mask==0x7f00) ||
(bSrc==0xff0000 && bmpImage->blue_mask==0x7f00)) {
/* ==== rgb 888 dib -> rgb 555 bmp ==== */
/* ==== bgr 888 dib -> bgr 555 bmp ==== */
convs->Convert_888_to_555_asis
(width,lines,
srcbits,linebytes,
dstbits,-bmpImage->bytes_per_line);
} else if ((rSrc==0xff && bmpImage->red_mask==0x7f00) ||
(bSrc==0xff && bmpImage->blue_mask==0x7f00)) {
/* ==== rgb 888 dib -> bgr 555 bmp ==== */
/* ==== bgr 888 dib -> rgb 555 bmp ==== */
convs->Convert_888_to_555_reverse
(width,lines,
srcbits,linebytes,
dstbits,-bmpImage->bytes_per_line);
} else {
goto notsupported;
}
} else if (bmpImage->green_mask==0x07e0) {
if ((rSrc==0xff0000 && bmpImage->red_mask==0xf800) ||
(bSrc==0xff0000 && bmpImage->blue_mask==0xf800)) {
/* ==== rgb 888 dib -> rgb 565 bmp ==== */
/* ==== bgr 888 dib -> bgr 565 bmp ==== */
convs->Convert_888_to_565_asis
(width,lines,
srcbits,linebytes,
dstbits,-bmpImage->bytes_per_line);
} else if ((rSrc==0xff && bmpImage->red_mask==0xf800) ||
(bSrc==0xff && bmpImage->blue_mask==0xf800)) {
/* ==== rgb 888 dib -> bgr 565 bmp ==== */
/* ==== bgr 888 dib -> rgb 565 bmp ==== */
convs->Convert_888_to_565_reverse
(width,lines,
srcbits,linebytes,
dstbits,-bmpImage->bytes_per_line);
} else {
goto notsupported;
}
} else {
goto notsupported;
}
}
break;
default:
notsupported:
WARN("from 24 bit DIB (%x,%x,%x) to unknown %d bit bitmap (%lx,%lx,%lx)\n",
rSrc, gSrc, bSrc, bmpImage->bits_per_pixel, bmpImage->red_mask,
bmpImage->green_mask, bmpImage->blue_mask );
/* fall through */
case 1:
case 4:
case 8:
{
/* ==== rgb 888 dib -> any bmp format ==== */
const BYTE* srcbyte;
/* Windows only supports one 24bpp DIB format: RGB888 */
srcbits+=left*3;
for (h = lines - 1; h >= 0; h--) {
srcbyte = srcbits;
for (x = left; x < width+left; x++) {
XPutPixel(bmpImage, x, h,
X11DRV_PALETTE_ToPhysical
(physDev, RGB(srcbyte[2], srcbyte[1], srcbyte[0])));
srcbyte+=3;
}
srcbits += linebytes;
}
}
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,
DWORD rDst, DWORD gDst, DWORD bDst,
XImage *bmpImage, DWORD linebytes )
{
DWORD x;
int h, width = min(srcwidth, dstwidth);
const dib_conversions *convs = (bmpImage->byte_order == LSBFirst) ? &dib_normal : &dib_src_byteswap;
if (lines < 0 )
{
lines = -lines;
dstbits = dstbits + ( linebytes * (lines-1) );
linebytes = -linebytes;
}
switch (bmpImage->depth)
{
case 24:
if (bmpImage->bits_per_pixel==24) {
const char* srcbits;
srcbits=bmpImage->data+(lines-1)*bmpImage->bytes_per_line;
if (bmpImage->green_mask!=0x00ff00 ||
(bmpImage->red_mask|bmpImage->blue_mask)!=0xff00ff) {
goto notsupported;
} else if (rDst==bmpImage->red_mask) {
/* ==== rgb 888 bmp -> rgb 888 dib ==== */
/* ==== bgr 888 bmp -> bgr 888 dib ==== */
convs->Convert_888_asis
(width,lines,
srcbits,-bmpImage->bytes_per_line,
dstbits,linebytes);
} else {
/* ==== rgb 888 bmp -> bgr 888 dib ==== */
/* ==== bgr 888 bmp -> rgb 888 dib ==== */
convs->Convert_888_reverse
(width,lines,
srcbits,-bmpImage->bytes_per_line,
dstbits,linebytes);
}
break;
}
/* fall through */
case 32:
{
const char* srcbits;
srcbits=bmpImage->data+(lines-1)*bmpImage->bytes_per_line;
if (bmpImage->green_mask!=0x00ff00 ||
(bmpImage->red_mask|bmpImage->blue_mask)!=0xff00ff) {
goto notsupported;
} else if (rDst==bmpImage->red_mask) {
/* ==== rgb 888 bmp -> rgb 0888 dib ==== */
/* ==== bgr 888 bmp -> bgr 0888 dib ==== */
convs->Convert_0888_to_888_asis
(width,lines,
srcbits,-bmpImage->bytes_per_line,
dstbits,linebytes);
} else {
/* ==== rgb 888 bmp -> bgr 0888 dib ==== */
/* ==== bgr 888 bmp -> rgb 0888 dib ==== */
convs->Convert_0888_to_888_reverse
(width,lines,
srcbits,-bmpImage->bytes_per_line,
dstbits,linebytes);
}
break;
}
case 15:
case 16:
{
const char* srcbits;
srcbits=bmpImage->data+(lines-1)*bmpImage->bytes_per_line;
if (bmpImage->green_mask==0x03e0) {
if ((rDst==0xff0000 && bmpImage->red_mask==0x7f00) ||
(bDst==0xff0000 && bmpImage->blue_mask==0x7f00)) {
/* ==== rgb 555 bmp -> rgb 888 dib ==== */
/* ==== bgr 555 bmp -> bgr 888 dib ==== */
convs->Convert_555_to_888_asis
(width,lines,
srcbits,-bmpImage->bytes_per_line,
dstbits,linebytes);
} else if ((rDst==0xff && bmpImage->red_mask==0x7f00) ||
(bDst==0xff && bmpImage->blue_mask==0x7f00)) {
/* ==== rgb 555 bmp -> bgr 888 dib ==== */
/* ==== bgr 555 bmp -> rgb 888 dib ==== */
convs->Convert_555_to_888_reverse
(width,lines,
srcbits,-bmpImage->bytes_per_line,
dstbits,linebytes);
} else {
goto notsupported;
}
} else if (bmpImage->green_mask==0x07e0) {
if ((rDst==0xff0000 && bmpImage->red_mask==0xf800) ||
(bDst==0xff0000 && bmpImage->blue_mask==0xf800)) {
/* ==== rgb 565 bmp -> rgb 888 dib ==== */
/* ==== bgr 565 bmp -> bgr 888 dib ==== */
convs->Convert_565_to_888_asis
(width,lines,
srcbits,-bmpImage->bytes_per_line,
dstbits,linebytes);
} else if ((rDst==0xff && bmpImage->red_mask==0xf800) ||
(bDst==0xff && bmpImage->blue_mask==0xf800)) {
/* ==== rgb 565 bmp -> bgr 888 dib ==== */
/* ==== bgr 565 bmp -> rgb 888 dib ==== */
convs->Convert_565_to_888_reverse
(width,lines,
srcbits,-bmpImage->bytes_per_line,
dstbits,linebytes);
} else {
goto notsupported;
}
} else {
goto notsupported;
}
}
break;
case 1:
case 4:
if (X11DRV_DIB_CheckMask(bmpImage->red_mask,bmpImage->green_mask,bmpImage->blue_mask)
&& srccolors) {
/* ==== pal 1 or 4 bmp -> rgb 888 dib ==== */
BYTE* dstbyte;
/* Windows only supports one 24bpp DIB format: rgb 888 */
for (h = lines - 1; h >= 0; h--) {
dstbyte=dstbits;
for (x = 0; x < width; x++) {
PALETTEENTRY srcval;
srcval=srccolors[XGetPixel(bmpImage, x, h)];
dstbyte[0]=srcval.peBlue;
dstbyte[1]=srcval.peGreen;
dstbyte[2]=srcval.peRed;
dstbyte+=3;
}
dstbits += linebytes;
}
} else {
goto notsupported;
}
break;
case 8:
if (X11DRV_DIB_CheckMask(bmpImage->red_mask,bmpImage->green_mask,bmpImage->blue_mask)
&& srccolors) {
/* ==== pal 8 bmp -> rgb 888 dib ==== */
const void* srcbits;
const BYTE* srcpixel;
BYTE* dstbyte;
/* Windows only supports one 24bpp DIB format: rgb 888 */
srcbits=bmpImage->data+(lines-1)*bmpImage->bytes_per_line;
for (h = lines - 1; h >= 0; h--) {
srcpixel=srcbits;
dstbyte=dstbits;
for (x = 0; x < width; x++ ) {
PALETTEENTRY srcval;
srcval=srccolors[*srcpixel++];
dstbyte[0]=srcval.peBlue;
dstbyte[1]=srcval.peGreen;
dstbyte[2]=srcval.peRed;
dstbyte+=3;
}
srcbits = (const char*)srcbits - bmpImage->bytes_per_line;
dstbits += linebytes;
}
} else {
goto notsupported;
}
break;
default:
notsupported:
{
/* ==== any bmp format -> 888 dib ==== */
BYTE* dstbyte;
WARN("from unknown %d bit bitmap (%lx,%lx,%lx) to 24 bit DIB (%x,%x,%x)\n",
bmpImage->depth, bmpImage->red_mask,
bmpImage->green_mask, bmpImage->blue_mask,
rDst, gDst, bDst );
/* Windows only supports one 24bpp DIB format: rgb 888 */
for (h = lines - 1; h >= 0; h--) {
dstbyte=dstbits;
for (x = 0; x < width; x++) {
COLORREF srcval=X11DRV_PALETTE_ToLogical
(XGetPixel( bmpImage, x, h ));
dstbyte[0]=GetBValue(srcval);
dstbyte[1]=GetGValue(srcval);
dstbyte[2]=GetRValue(srcval);
dstbyte+=3;
}
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,
X11DRV_PDEVICE *physDev,
DWORD rSrc, DWORD gSrc, DWORD bSrc,
XImage *bmpImage,
DWORD linebytes)
{
DWORD x;
const DWORD *ptr;
int h, width = min(srcwidth, dstwidth);
const dib_conversions *convs = (bmpImage->byte_order == LSBFirst) ? &dib_normal : &dib_dst_byteswap;
if (lines < 0 )
{
lines = -lines;
srcbits = srcbits + ( linebytes * (lines-1) );
linebytes = -linebytes;
}
ptr = (const DWORD *) srcbits + left;
switch (bmpImage->depth)
{
case 24:
if (bmpImage->bits_per_pixel==24) {
char* dstbits;
srcbits=srcbits+left*4;
dstbits=bmpImage->data+left*3+(lines-1)*bmpImage->bytes_per_line;
if (rSrc==bmpImage->red_mask && gSrc==bmpImage->green_mask && bSrc==bmpImage->blue_mask) {
/* ==== rgb 0888 dib -> rgb 888 bmp ==== */
/* ==== bgr 0888 dib -> bgr 888 bmp ==== */
convs->Convert_0888_to_888_asis
(width,lines,
srcbits,linebytes,
dstbits,-bmpImage->bytes_per_line);
} else if (bmpImage->green_mask!=0x00ff00 ||
(bmpImage->red_mask|bmpImage->blue_mask)!=0xff00ff) {
goto notsupported;
/* the tests below assume sane bmpImage masks */
} else if (rSrc==bmpImage->blue_mask && gSrc==bmpImage->green_mask && bSrc==bmpImage->red_mask) {
/* ==== rgb 0888 dib -> bgr 888 bmp ==== */
/* ==== bgr 0888 dib -> rgb 888 bmp ==== */
convs->Convert_0888_to_888_reverse
(width,lines,
srcbits,linebytes,
dstbits,-bmpImage->bytes_per_line);
} else if (bmpImage->blue_mask==0xff) {
/* ==== any 0888 dib -> rgb 888 bmp ==== */
convs->Convert_any0888_to_rgb888
(width,lines,
srcbits,linebytes,
rSrc,gSrc,bSrc,
dstbits,-bmpImage->bytes_per_line);
} else {
/* ==== any 0888 dib -> bgr 888 bmp ==== */
convs->Convert_any0888_to_bgr888
(width,lines,
srcbits,linebytes,
rSrc,gSrc,bSrc,
dstbits,-bmpImage->bytes_per_line);
}
break;
}
/* fall through */
case 32:
{
char* dstbits;
srcbits=srcbits+left*4;
dstbits=bmpImage->data+left*4+(lines-1)*bmpImage->bytes_per_line;
if (gSrc==bmpImage->green_mask) {
if (rSrc==bmpImage->red_mask && bSrc==bmpImage->blue_mask) {
/* ==== rgb 0888 dib -> rgb 0888 bmp ==== */
/* ==== bgr 0888 dib -> bgr 0888 bmp ==== */
convs->Convert_0888_asis
(width,lines,
srcbits,linebytes,
dstbits,-bmpImage->bytes_per_line);
} else if (bmpImage->green_mask!=0x00ff00 ||
(bmpImage->red_mask|bmpImage->blue_mask)!=0xff00ff) {
goto notsupported;
/* the tests below assume sane bmpImage masks */
} else if (rSrc==bmpImage->blue_mask && bSrc==bmpImage->red_mask) {
/* ==== rgb 0888 dib -> bgr 0888 bmp ==== */
/* ==== bgr 0888 dib -> rgb 0888 bmp ==== */
convs->Convert_0888_reverse
(width,lines,
srcbits,linebytes,
dstbits,-bmpImage->bytes_per_line);
} else {
/* ==== any 0888 dib -> any 0888 bmp ==== */
convs->Convert_0888_any
(width,lines,
srcbits,linebytes,
rSrc,gSrc,bSrc,
dstbits,-bmpImage->bytes_per_line,
bmpImage->red_mask,bmpImage->green_mask,bmpImage->blue_mask);
}
} else if (bmpImage->green_mask!=0x00ff00 ||
(bmpImage->red_mask|bmpImage->blue_mask)!=0xff00ff) {
goto notsupported;
/* the tests below assume sane bmpImage masks */
} else {
/* ==== any 0888 dib -> any 0888 bmp ==== */
convs->Convert_0888_any
(width,lines,
srcbits,linebytes,
rSrc,gSrc,bSrc,
dstbits,-bmpImage->bytes_per_line,
bmpImage->red_mask,bmpImage->green_mask,bmpImage->blue_mask);
}
}
break;
case 15:
case 16:
{
char* dstbits;
srcbits=srcbits+left*4;
dstbits=bmpImage->data+left*2+(lines-1)*bmpImage->bytes_per_line;
if (rSrc==0xff0000 && gSrc==0x00ff00 && bSrc==0x0000ff) {
if (bmpImage->green_mask==0x03e0) {
if (bmpImage->red_mask==0x7f00) {
/* ==== rgb 0888 dib -> rgb 555 bmp ==== */
convs->Convert_0888_to_555_asis
(width,lines,
srcbits,linebytes,
dstbits,-bmpImage->bytes_per_line);
} else if (bmpImage->blue_mask==0x7f00) {
/* ==== rgb 0888 dib -> bgr 555 bmp ==== */
convs->Convert_0888_to_555_reverse
(width,lines,
srcbits,linebytes,
dstbits,-bmpImage->bytes_per_line);
} else {
goto notsupported;
}
} else if (bmpImage->green_mask==0x07e0) {
if (bmpImage->red_mask==0xf800) {
/* ==== rgb 0888 dib -> rgb 565 bmp ==== */
convs->Convert_0888_to_565_asis
(width,lines,
srcbits,linebytes,
dstbits,-bmpImage->bytes_per_line);
} else if (bmpImage->blue_mask==0xf800) {
/* ==== rgb 0888 dib -> bgr 565 bmp ==== */
convs->Convert_0888_to_565_reverse
(width,lines,
srcbits,linebytes,
dstbits,-bmpImage->bytes_per_line);
} else {
goto notsupported;
}
} else {
goto notsupported;
}
} else if (rSrc==0x0000ff && gSrc==0x00ff00 && bSrc==0xff0000) {
if (bmpImage->green_mask==0x03e0) {
if (bmpImage->blue_mask==0x7f00) {
/* ==== bgr 0888 dib -> bgr 555 bmp ==== */
convs->Convert_0888_to_555_asis
(width,lines,
srcbits,linebytes,
dstbits,-bmpImage->bytes_per_line);
} else if (bmpImage->red_mask==0x7f00) {
/* ==== bgr 0888 dib -> rgb 555 bmp ==== */
convs->Convert_0888_to_555_reverse
(width,lines,
srcbits,linebytes,
dstbits,-bmpImage->bytes_per_line);
} else {
goto notsupported;
}
} else if (bmpImage->green_mask==0x07e0) {
if (bmpImage->blue_mask==0xf800) {
/* ==== bgr 0888 dib -> bgr 565 bmp ==== */
convs->Convert_0888_to_565_asis
(width,lines,
srcbits,linebytes,
dstbits,-bmpImage->bytes_per_line);
} else if (bmpImage->red_mask==0xf800) {
/* ==== bgr 0888 dib -> rgb 565 bmp ==== */
convs->Convert_0888_to_565_reverse
(width,lines,
srcbits,linebytes,
dstbits,-bmpImage->bytes_per_line);
} else {
goto notsupported;
}
} else {
goto notsupported;
}
} else {
if (bmpImage->green_mask==0x03e0 &&
(bmpImage->red_mask==0x7f00 ||
bmpImage->blue_mask==0x7f00)) {
/* ==== any 0888 dib -> rgb or bgr 555 bmp ==== */
convs->Convert_any0888_to_5x5
(width,lines,
srcbits,linebytes,
rSrc,gSrc,bSrc,
dstbits,-bmpImage->bytes_per_line,
bmpImage->red_mask,bmpImage->green_mask,bmpImage->blue_mask);
} else if (bmpImage->green_mask==0x07e0 &&
(bmpImage->red_mask==0xf800 ||
bmpImage->blue_mask==0xf800)) {
/* ==== any 0888 dib -> rgb or bgr 565 bmp ==== */
convs->Convert_any0888_to_5x5
(width,lines,
srcbits,linebytes,
rSrc,gSrc,bSrc,
dstbits,-bmpImage->bytes_per_line,
bmpImage->red_mask,bmpImage->green_mask,bmpImage->blue_mask);
} else {
goto notsupported;
}
}
}
break;
default:
notsupported:
WARN("from 32 bit DIB (%x,%x,%x) to unknown %d bit bitmap (%lx,%lx,%lx)\n",
rSrc, gSrc, bSrc, bmpImage->bits_per_pixel, bmpImage->red_mask,
bmpImage->green_mask, bmpImage->blue_mask );
/* fall through */
case 1:
case 4:
case 8:
{
/* ==== any 0888 dib -> pal 1, 4 or 8 bmp ==== */
const DWORD* srcpixel;
int rShift,gShift,bShift;
rShift=X11DRV_DIB_MaskToShift(rSrc);
gShift=X11DRV_DIB_MaskToShift(gSrc);
bShift=X11DRV_DIB_MaskToShift(bSrc);
srcbits+=left*4;
for (h = lines - 1; h >= 0; h--) {
srcpixel=(const DWORD*)srcbits;
for (x = left; x < width+left; x++) {
DWORD srcvalue;
BYTE red,green,blue;
srcvalue=*srcpixel++;
red= (srcvalue >> rShift) & 0xff;
green=(srcvalue >> gShift) & 0xff;
blue= (srcvalue >> bShift) & 0xff;
XPutPixel(bmpImage, x, h, X11DRV_PALETTE_ToPhysical
(physDev, RGB(red,green,blue)));
}
srcbits += linebytes;
}
}
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,
DWORD rDst, DWORD gDst, DWORD bDst,
XImage *bmpImage, DWORD linebytes )
{
DWORD x;
int h, width = min(srcwidth, dstwidth);
BYTE *bits;
const dib_conversions *convs = (bmpImage->byte_order == LSBFirst) ? &dib_normal : &dib_src_byteswap;
if (lines < 0 )
{
lines = -lines;
dstbits = dstbits + ( linebytes * (lines-1) );
linebytes = -linebytes;
}
bits = dstbits;
switch (bmpImage->depth)
{
case 24:
if (bmpImage->bits_per_pixel==24) {
const void* srcbits;
srcbits=bmpImage->data+(lines-1)*bmpImage->bytes_per_line;
if (rDst==bmpImage->red_mask && gDst==bmpImage->green_mask && bDst==bmpImage->blue_mask) {
/* ==== rgb 888 bmp -> rgb 0888 dib ==== */
/* ==== bgr 888 bmp -> bgr 0888 dib ==== */
convs->Convert_888_to_0888_asis
(width,lines,
srcbits,-bmpImage->bytes_per_line,
dstbits,linebytes);
} else if (bmpImage->green_mask!=0x00ff00 ||
(bmpImage->red_mask|bmpImage->blue_mask)!=0xff00ff) {
goto notsupported;
/* the tests below assume sane bmpImage masks */
} else if (rDst==bmpImage->blue_mask && gDst==bmpImage->green_mask && bDst==bmpImage->red_mask) {
/* ==== rgb 888 bmp -> bgr 0888 dib ==== */
/* ==== bgr 888 bmp -> rgb 0888 dib ==== */
convs->Convert_888_to_0888_reverse
(width,lines,
srcbits,-bmpImage->bytes_per_line,
dstbits,linebytes);
} else if (bmpImage->blue_mask==0xff) {
/* ==== rgb 888 bmp -> any 0888 dib ==== */
convs->Convert_rgb888_to_any0888
(width,lines,
srcbits,-bmpImage->bytes_per_line,
dstbits,linebytes,
rDst,gDst,bDst);
} else {
/* ==== bgr 888 bmp -> any 0888 dib ==== */
convs->Convert_bgr888_to_any0888
(width,lines,
srcbits,-bmpImage->bytes_per_line,
dstbits,linebytes,
rDst,gDst,bDst);
}
break;
}
/* fall through */
case 32:
{
const char* srcbits;
srcbits=bmpImage->data+(lines-1)*bmpImage->bytes_per_line;
if (gDst==bmpImage->green_mask) {
if (rDst==bmpImage->red_mask && bDst==bmpImage->blue_mask) {
/* ==== rgb 0888 bmp -> rgb 0888 dib ==== */
/* ==== bgr 0888 bmp -> bgr 0888 dib ==== */
convs->Convert_0888_asis
(width,lines,
srcbits,-bmpImage->bytes_per_line,
dstbits,linebytes);
} else if (bmpImage->green_mask!=0x00ff00 ||
(bmpImage->red_mask|bmpImage->blue_mask)!=0xff00ff) {
goto notsupported;
/* the tests below assume sane bmpImage masks */
} else if (rDst==bmpImage->blue_mask && bDst==bmpImage->red_mask) {
/* ==== rgb 0888 bmp -> bgr 0888 dib ==== */
/* ==== bgr 0888 bmp -> rgb 0888 dib ==== */
convs->Convert_0888_reverse
(width,lines,
srcbits,-bmpImage->bytes_per_line,
dstbits,linebytes);
} else {
/* ==== any 0888 bmp -> any 0888 dib ==== */
convs->Convert_0888_any
(width,lines,
srcbits,-bmpImage->bytes_per_line,
bmpImage->red_mask,bmpImage->green_mask,bmpImage->blue_mask,
dstbits,linebytes,
rDst,gDst,bDst);
}
} else if (bmpImage->green_mask!=0x00ff00 ||
(bmpImage->red_mask|bmpImage->blue_mask)!=0xff00ff) {
goto notsupported;
/* the tests below assume sane bmpImage masks */
} else {
/* ==== any 0888 bmp -> any 0888 dib ==== */
convs->Convert_0888_any
(width,lines,
srcbits,-bmpImage->bytes_per_line,
bmpImage->red_mask,bmpImage->green_mask,bmpImage->blue_mask,
dstbits,linebytes,
rDst,gDst,bDst);
}
}
break;
case 15:
case 16:
{
const char* srcbits;
srcbits=bmpImage->data+(lines-1)*bmpImage->bytes_per_line;
if (rDst==0xff0000 && gDst==0x00ff00 && bDst==0x0000ff) {
if (bmpImage->green_mask==0x03e0) {
if (bmpImage->red_mask==0x7f00) {
/* ==== rgb 555 bmp -> rgb 0888 dib ==== */
convs->Convert_555_to_0888_asis
(width,lines,
srcbits,-bmpImage->bytes_per_line,
dstbits,linebytes);
} else if (bmpImage->blue_mask==0x7f00) {
/* ==== bgr 555 bmp -> rgb 0888 dib ==== */
convs->Convert_555_to_0888_reverse
(width,lines,
srcbits,-bmpImage->bytes_per_line,
dstbits,linebytes);
} else {
goto notsupported;
}
} else if (bmpImage->green_mask==0x07e0) {
if (bmpImage->red_mask==0xf800) {
/* ==== rgb 565 bmp -> rgb 0888 dib ==== */
convs->Convert_565_to_0888_asis
(width,lines,
srcbits,-bmpImage->bytes_per_line,
dstbits,linebytes);
} else if (bmpImage->blue_mask==0xf800) {
/* ==== bgr 565 bmp -> rgb 0888 dib ==== */
convs->Convert_565_to_0888_reverse
(width,lines,
srcbits,-bmpImage->bytes_per_line,
dstbits,linebytes);
} else {
goto notsupported;
}
} else {
goto notsupported;
}
} else if (rDst==0x0000ff && gDst==0x00ff00 && bDst==0xff0000) {
if (bmpImage->green_mask==0x03e0) {
if (bmpImage->blue_mask==0x7f00) {
/* ==== bgr 555 bmp -> bgr 0888 dib ==== */
convs->Convert_555_to_0888_asis
(width,lines,
srcbits,-bmpImage->bytes_per_line,
dstbits,linebytes);
} else if (bmpImage->red_mask==0x7f00) {
/* ==== rgb 555 bmp -> bgr 0888 dib ==== */
convs->Convert_555_to_0888_reverse
(width,lines,
srcbits,-bmpImage->bytes_per_line,
dstbits,linebytes);
} else {
goto notsupported;
}
} else if (bmpImage->green_mask==0x07e0) {
if (bmpImage->blue_mask==0xf800) {
/* ==== bgr 565 bmp -> bgr 0888 dib ==== */
convs->Convert_565_to_0888_asis
(width,lines,
srcbits,-bmpImage->bytes_per_line,
dstbits,linebytes);
} else if (bmpImage->red_mask==0xf800) {
/* ==== rgb 565 bmp -> bgr 0888 dib ==== */
convs->Convert_565_to_0888_reverse
(width,lines,
srcbits,-bmpImage->bytes_per_line,
dstbits,linebytes);
} else {
goto notsupported;
}
} else {
goto notsupported;
}
} else {
if (bmpImage->green_mask==0x03e0 &&
(bmpImage->red_mask==0x7f00 ||
bmpImage->blue_mask==0x7f00)) {
/* ==== rgb or bgr 555 bmp -> any 0888 dib ==== */
convs->Convert_5x5_to_any0888
(width,lines,
srcbits,-bmpImage->bytes_per_line,
bmpImage->red_mask,bmpImage->green_mask,bmpImage->blue_mask,
dstbits,linebytes,
rDst,gDst,bDst);
} else if (bmpImage->green_mask==0x07e0 &&
(bmpImage->red_mask==0xf800 ||
bmpImage->blue_mask==0xf800)) {
/* ==== rgb or bgr 565 bmp -> any 0888 dib ==== */
convs->Convert_5x5_to_any0888
(width,lines,
srcbits,-bmpImage->bytes_per_line,
bmpImage->red_mask,bmpImage->green_mask,bmpImage->blue_mask,
dstbits,linebytes,
rDst,gDst,bDst);
} else {
goto notsupported;
}
}
}
break;
case 1:
case 4:
if (X11DRV_DIB_CheckMask(bmpImage->red_mask,bmpImage->green_mask,bmpImage->blue_mask)
&& srccolors) {
/* ==== pal 1 or 4 bmp -> any 0888 dib ==== */
int rShift,gShift,bShift;
DWORD* dstpixel;
rShift=X11DRV_DIB_MaskToShift(rDst);
gShift=X11DRV_DIB_MaskToShift(gDst);
bShift=X11DRV_DIB_MaskToShift(bDst);
for (h = lines - 1; h >= 0; h--) {
dstpixel=(DWORD*)dstbits;
for (x = 0; x < width; x++) {
PALETTEENTRY srcval;
srcval = srccolors[XGetPixel(bmpImage, x, h)];
*dstpixel++=(srcval.peRed << rShift) |
(srcval.peGreen << gShift) |
(srcval.peBlue << bShift);
}
dstbits += linebytes;
}
} else {
goto notsupported;
}
break;
case 8:
if (X11DRV_DIB_CheckMask(bmpImage->red_mask,bmpImage->green_mask,bmpImage->blue_mask)
&& srccolors) {
/* ==== pal 8 bmp -> any 0888 dib ==== */
int rShift,gShift,bShift;
const void* srcbits;
const BYTE* srcpixel;
DWORD* dstpixel;
rShift=X11DRV_DIB_MaskToShift(rDst);
gShift=X11DRV_DIB_MaskToShift(gDst);
bShift=X11DRV_DIB_MaskToShift(bDst);
srcbits=bmpImage->data+(lines-1)*bmpImage->bytes_per_line;
for (h = lines - 1; h >= 0; h--) {
srcpixel=srcbits;
dstpixel=(DWORD*)dstbits;
for (x = 0; x < width; x++) {
PALETTEENTRY srcval;
srcval=srccolors[*srcpixel++];
*dstpixel++=(srcval.peRed << rShift) |
(srcval.peGreen << gShift) |
(srcval.peBlue << bShift);
}
srcbits = (const char*)srcbits - bmpImage->bytes_per_line;
dstbits += linebytes;
}
} else {
goto notsupported;
}
break;
default:
notsupported:
{
/* ==== any bmp format -> any 0888 dib ==== */
int rShift,gShift,bShift;
DWORD* dstpixel;
WARN("from unknown %d bit bitmap (%lx,%lx,%lx) to 32 bit DIB (%x,%x,%x)\n",
bmpImage->depth, bmpImage->red_mask,
bmpImage->green_mask, bmpImage->blue_mask,
rDst,gDst,bDst);
rShift=X11DRV_DIB_MaskToShift(rDst);
gShift=X11DRV_DIB_MaskToShift(gDst);
bShift=X11DRV_DIB_MaskToShift(bDst);
for (h = lines - 1; h >= 0; h--) {
dstpixel=(DWORD*)dstbits;
for (x = 0; x < width; x++) {
COLORREF srcval;
srcval=X11DRV_PALETTE_ToLogical(XGetPixel(bmpImage, x, h));
*dstpixel++=(GetRValue(srcval) << rShift) |
(GetGValue(srcval) << gShift) |
(GetBValue(srcval) << bShift);
}
dstbits += linebytes;
}
}
break;
}
}
static int XGetSubImageErrorHandler(Display *dpy, XErrorEvent *event, void *arg)
{
return (event->request_code == X_GetImage && event->error_code == BadMatch);
}
/***********************************************************************
* X11DRV_DIB_SetImageBits_GetSubImage
*
* Helper for X11DRV_DIB_SetImageBits
*/
static void X11DRV_DIB_SetImageBits_GetSubImage(
const X11DRV_DIB_IMAGEBITS_DESCR *descr, XImage *bmpImage)
{
/* compressed bitmaps may contain gaps in them. So make a copy
* of the existing pixels first */
RECT bmprc, rc;
SetRect( &bmprc, descr->xDest, descr->yDest,
descr->xDest + descr->width , descr->yDest + descr->height );
GetRgnBox( descr->physDev->region, &rc );
/* convert from dc to drawable origin */
OffsetRect( &rc, descr->physDev->dc_rect.left, descr->physDev->dc_rect.top);
/* clip visible rect with bitmap */
if( IntersectRect( &rc, &rc, &bmprc))
{
X11DRV_expect_error( gdi_display, XGetSubImageErrorHandler, NULL );
XGetSubImage( gdi_display, descr->drawable, rc.left, rc.top,
rc.right - rc.left, rc.bottom - rc.top, AllPlanes,
ZPixmap, bmpImage,
descr->xSrc + rc.left - bmprc.left,
descr->ySrc + rc.top - bmprc.top);
X11DRV_check_error();
}
}
/***********************************************************************
* 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;
}
}
wine_tsx11_unlock();
TRACE("Dib: depth=%d r=%x g=%x b=%x\n",
descr->infoBpp,descr->rMask,descr->gMask,descr->bMask);
TRACE("Bmp: depth=%d/%d r=%lx g=%lx b=%lx\n",
bmpImage->depth,bmpImage->bits_per_pixel,
bmpImage->red_mask,bmpImage->green_mask,bmpImage->blue_mask);
/* 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) {
X11DRV_DIB_SetImageBits_GetSubImage( descr, bmpImage);
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) {
X11DRV_DIB_SetImageBits_GetSubImage( descr, bmpImage);
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->physDev,
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->physDev,
descr->rMask, descr->gMask, descr->bMask,
bmpImage, descr->dibpitch);
break;
case 32:
X11DRV_DIB_SetImageBits_32( descr->lines, descr->bits,
descr->infoWidth, descr->width,
descr->xSrc, descr->physDev,
descr->rMask, descr->gMask, descr->bMask,
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);
wine_tsx11_lock();
#ifdef HAVE_LIBXXSHM
if (descr->image && 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;
}
}
#ifdef HAVE_LIBXXSHM
/* We must not call XShmGetImage() with a bitmap which is bigger than the available area.
If we do, XShmGetImage() will fail (X exception), as it checks for this internally. */
if((descr->image && descr->useShm) && (bmpImage->width <= (descr->width - descr->xSrc))
&& (bmpImage->height <= (descr->height - descr->ySrc)))
{
int saveRed, saveGreen, saveBlue;
TRACE("XShmGetImage(%p, %ld, %p, %d, %d, %ld)\n",
gdi_display, descr->drawable, bmpImage,
descr->xSrc, descr->ySrc, AllPlanes);
/* We must save and restore the bmpImage's masks in order
* to preserve them across the call to XShmGetImage, which
* decides to eliminate them since it doesn't happen to know
* what the format of the image is supposed to be, even though
* we do. */
saveRed = bmpImage->red_mask;
saveBlue= bmpImage->blue_mask;
saveGreen = bmpImage->green_mask;
XShmGetImage( gdi_display, descr->drawable, bmpImage,
descr->xSrc, descr->ySrc, AllPlanes);
bmpImage->red_mask = saveRed;
bmpImage->blue_mask = saveBlue;
bmpImage->green_mask = saveGreen;
}
else
#endif /* HAVE_LIBXXSHM */
{
TRACE("XGetSubImage(%p,%ld,%d,%d,%d,%d,%ld,%d,%p,%d,%d)\n",
gdi_display, 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 );
}
wine_tsx11_unlock();
TRACE("Dib: depth=%2d r=%x g=%x b=%x\n",
descr->infoBpp,descr->rMask,descr->gMask,descr->bMask);
TRACE("Bmp: depth=%2d/%2d r=%lx g=%lx b=%lx\n",
bmpImage->depth,bmpImage->bits_per_pixel,
bmpImage->red_mask,bmpImage->green_mask,bmpImage->blue_mask);
/* 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");
if(descr->sizeImage < X11DRV_DIB_GetDIBWidthBytes( descr->infoWidth, 4 ) * abs(descr->lines))
break;
}
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");
if(descr->sizeImage < X11DRV_DIB_GetDIBWidthBytes( descr->infoWidth, 8 ) * abs(descr->lines))
break;
}
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,
descr->rMask, descr->gMask, descr->bMask,
bmpImage, descr->dibpitch);
break;
case 32:
X11DRV_DIB_GetImageBits_32( descr->lines, (LPVOID)descr->bits,
descr->infoWidth, descr->width,
descr->palentry,
descr->rMask, descr->gMask, descr->bMask,
bmpImage, descr->dibpitch);
break;
default:
WARN("(%d): Invalid depth\n", descr->infoBpp );
break;
}
if (!descr->image)
{
wine_tsx11_lock();
XDestroyImage( bmpImage );
wine_tsx11_unlock();
}
return lines;
}
/*************************************************************************
* X11DRV_SetDIBitsToDevice
*
*/
INT X11DRV_SetDIBitsToDevice( X11DRV_PDEVICE *physDev, 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;
INT result;
LONG width, height;
BOOL top_down;
POINT pt;
int rop = X11DRV_XROPfunction[GetROP2(physDev->hdc) - 1];
if (DIB_GetBitmapInfo( &info->bmiHeader, &width, &height,
&descr.infoBpp, &descr.compression ) == -1)
return 0;
top_down = (height < 0);
if (top_down) height = -height;
pt.x = xDest;
pt.y = yDest;
LPtoDP(physDev->hdc, &pt, 1);
if (!lines || (startscan >= height)) return 0;
if (!top_down && startscan + lines > height) lines = height - startscan;
/* make xSrc,ySrc point to the upper-left corner, not the lower-left one,
* and clamp all values to fit inside [startscan,startscan+lines]
*/
if (ySrc + cy <= startscan + lines)
{
UINT y = startscan + lines - (ySrc + cy);
if (ySrc < startscan) cy -= (startscan - ySrc);
if (!top_down)
{
/* avoid getting unnecessary lines */
ySrc = 0;
if (y >= lines) return 0;
lines -= y;
}
else
{
if (y >= lines) return lines;
ySrc = y; /* need to get all lines in top down mode */
}
}
else
{
if (ySrc >= startscan + lines) return lines;
pt.y += ySrc + cy - (startscan + lines);
cy = startscan + lines - ySrc;
ySrc = 0;
if (cy > lines) cy = lines;
}
if (xSrc >= width) return lines;
if (xSrc + cx >= width) cx = width - xSrc;
if (!cx || !cy) return lines;
/* Update the pixmap from the DIB section */
X11DRV_LockDIBSection(physDev, DIB_Status_GdiMod);
X11DRV_SetupGCForText( physDev ); /* To have the correct colors */
wine_tsx11_lock();
XSetFunction(gdi_display, physDev->gc, rop);
wine_tsx11_unlock();
switch (descr.infoBpp)
{
case 1:
case 4:
case 8:
descr.colorMap = (RGBQUAD *)X11DRV_DIB_BuildColorMap(
physDev, coloruse,
physDev->depth, 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) ? *(const DWORD *)info->bmiColors : 0x7c00;
descr.gMask = (descr.compression == BI_BITFIELDS) ? *((const DWORD *)info->bmiColors + 1) : 0x03e0;
descr.bMask = (descr.compression == BI_BITFIELDS) ? *((const DWORD *)info->bmiColors + 2) : 0x001f;
descr.colorMap = 0;
break;
case 24:
case 32:
descr.rMask = (descr.compression == BI_BITFIELDS) ? *(const DWORD *)info->bmiColors : 0xff0000;
descr.gMask = (descr.compression == BI_BITFIELDS) ? *((const DWORD *)info->bmiColors + 1) : 0x00ff00;
descr.bMask = (descr.compression == BI_BITFIELDS) ? *((const DWORD *)info->bmiColors + 2) : 0x0000ff;
descr.colorMap = 0;
break;
}
descr.physDev = physDev;
descr.bits = bits;
descr.image = NULL;
descr.palentry = NULL;
descr.lines = top_down ? -lines : lines;
descr.infoWidth = width;
descr.depth = physDev->depth;
descr.drawable = physDev->drawable;
descr.gc = physDev->gc;
descr.xSrc = xSrc;
descr.ySrc = ySrc;
descr.xDest = physDev->dc_rect.left + pt.x;
descr.yDest = physDev->dc_rect.top + pt.y;
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);
/* Update the DIBSection of the pixmap */
X11DRV_UnlockDIBSection(physDev, TRUE);
return result;
}
/***********************************************************************
* SetDIBits (X11DRV.@)
*/
INT X11DRV_SetDIBits( X11DRV_PDEVICE *physDev, HBITMAP hbitmap, UINT startscan,
UINT lines, LPCVOID bits, const BITMAPINFO *info, UINT coloruse )
{
X_PHYSBITMAP *physBitmap = X11DRV_get_phys_bitmap( hbitmap );
X11DRV_DIB_IMAGEBITS_DESCR descr;
BITMAP bitmap;
LONG width, height, tmpheight;
INT result;
descr.physDev = physDev;
if (!physBitmap) return 0;
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 (!GetObjectW( hbitmap, sizeof(bitmap), &bitmap )) return 0;
if (startscan + lines > height) lines = height - startscan;
switch (descr.infoBpp)
{
case 1:
case 4:
case 8:
descr.colorMap = (RGBQUAD *)X11DRV_DIB_BuildColorMap(
descr.physDev, coloruse,
physBitmap->pixmap_depth,
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) ? *(const DWORD *)info->bmiColors : 0x7c00;
descr.gMask = (descr.compression == BI_BITFIELDS) ? *((const DWORD *)info->bmiColors + 1) : 0x03e0;
descr.bMask = (descr.compression == BI_BITFIELDS) ? *((const DWORD *)info->bmiColors + 2) : 0x001f;
descr.colorMap = 0;
break;
case 24:
case 32:
descr.rMask = (descr.compression == BI_BITFIELDS) ? *(const DWORD *)info->bmiColors : 0xff0000;
descr.gMask = (descr.compression == BI_BITFIELDS) ? *((const DWORD *)info->bmiColors + 1) : 0x00ff00;
descr.bMask = (descr.compression == BI_BITFIELDS) ? *((const DWORD *)info->bmiColors + 2) : 0x0000ff;
descr.colorMap = 0;
break;
default: break;
}
descr.bits = bits;
descr.image = NULL;
descr.palentry = NULL;
descr.infoWidth = width;
descr.lines = tmpheight >= 0 ? lines : -lines;
descr.depth = physBitmap->pixmap_depth;
descr.drawable = physBitmap->pixmap;
descr.gc = BITMAP_GC(physBitmap);
descr.xSrc = 0;
descr.ySrc = 0;
descr.xDest = 0;
descr.yDest = height - startscan - lines;
descr.width = bitmap.bmWidth;
descr.height = lines;
descr.useShm = FALSE;
descr.dibpitch = ((descr.infoWidth * descr.infoBpp + 31) &~31) / 8;
X11DRV_DIB_Lock( physBitmap, DIB_Status_GdiMod );
result = X11DRV_DIB_SetImageBits( &descr );
/* optimisation for the case where the input bits are in exactly the same
* format as the internal representation and copying to the app bits is
* cheap - saves a round trip to the X server */
if (descr.compression == BI_RGB &&
coloruse == DIB_RGB_COLORS &&
descr.infoBpp == bitmap.bmBitsPixel &&
physBitmap->base && physBitmap->size < 65536)
{
unsigned int srcwidthb = bitmap.bmWidthBytes;
int dstwidthb = X11DRV_DIB_GetDIBWidthBytes( width, descr.infoBpp );
LPBYTE dbits = physBitmap->base, sbits = (LPBYTE)bits + (startscan * srcwidthb);
int widthb;
UINT y;
TRACE("syncing compatible set bits to app bits\n");
if ((tmpheight < 0) ^ (bitmap.bmHeight < 0))
{
dbits = (LPBYTE)bits + (dstwidthb * (lines-1));
dstwidthb = -dstwidthb;
}
X11DRV_DIB_DoProtectDIBSection( physBitmap, PAGE_READWRITE );
widthb = min(srcwidthb, abs(dstwidthb));
for (y = 0; y < lines; y++, dbits += dstwidthb, sbits += srcwidthb)
memcpy(dbits, sbits, widthb);
X11DRV_DIB_DoProtectDIBSection( physBitmap, PAGE_READONLY );
physBitmap->status = DIB_Status_InSync;
}
X11DRV_DIB_Unlock( physBitmap, TRUE );
HeapFree(GetProcessHeap(), 0, descr.colorMap);
return result;
}
/***********************************************************************
* GetDIBits (X11DRV.@)
*/
INT X11DRV_GetDIBits( X11DRV_PDEVICE *physDev, HBITMAP hbitmap, UINT startscan, UINT lines,
LPVOID bits, BITMAPINFO *info, UINT coloruse )
{
X_PHYSBITMAP *physBitmap = X11DRV_get_phys_bitmap( hbitmap );
DIBSECTION dib;
X11DRV_DIB_IMAGEBITS_DESCR descr;
PALETTEENTRY palette[256];
size_t obj_size;
int height;
LONG width, tempHeight;
int bitmap_type;
BOOL core_header;
void* colorPtr;
GetPaletteEntries( GetCurrentObject( physDev->hdc, OBJ_PAL ), 0, 256, palette );
if (!physBitmap) return 0;
if (!(obj_size = GetObjectW( hbitmap, sizeof(dib), &dib ))) return 0;
bitmap_type = DIB_GetBitmapInfo( (BITMAPINFOHEADER*)info, &width, &tempHeight, &descr.infoBpp, &descr.compression);
descr.lines = tempHeight;
if (bitmap_type == -1)
{
ERR("Invalid bitmap\n");
return 0;
}
core_header = (bitmap_type == 0);
colorPtr = (LPBYTE) info + (WORD) info->bmiHeader.biSize;
TRACE("%u scanlines of (%i,%i) -> (%i,%i) starting from %u\n",
lines, dib.dsBm.bmWidth, dib.dsBm.bmHeight, width, descr.lines, startscan);
if( lines > dib.dsBm.bmHeight ) lines = dib.dsBm.bmHeight;
height = descr.lines;
if (height < 0) height = -height;
if( lines > height ) lines = height;
/* Top-down images have a negative biHeight, the scanlines of these 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( descr.lines < 0 && lines > 0) lines = -lines;
if( startscan >= dib.dsBm.bmHeight ) return 0;
descr.colorMap = NULL;
switch (descr.infoBpp)
{
case 1:
case 4:
case 8:
descr.rMask= descr.gMask = descr.bMask = 0;
if(coloruse == DIB_RGB_COLORS)
descr.colorMap = colorPtr;
else {
int num_colors = 1 << descr.infoBpp, i;
RGBQUAD *rgb;
COLORREF colref;
WORD *index = (WORD*)colorPtr;
descr.colorMap = rgb = HeapAlloc(GetProcessHeap(), 0, num_colors * sizeof(RGBQUAD));
for(i = 0; i < num_colors; i++, rgb++, index++) {
colref = X11DRV_PALETTE_ToLogical(X11DRV_PALETTE_ToPhysical(physDev, PALETTEINDEX(*index)));
rgb->rgbRed = GetRValue(colref);
rgb->rgbGreen = GetGValue(colref);
rgb->rgbBlue = GetBValue(colref);
rgb->rgbReserved = 0;
}
}
break;
case 15:
case 16:
descr.rMask = (descr.compression == BI_BITFIELDS) ? *(const DWORD *)info->bmiColors : 0x7c00;
descr.gMask = (descr.compression == BI_BITFIELDS) ? *((const DWORD *)info->bmiColors + 1) : 0x03e0;
descr.bMask = (descr.compression == BI_BITFIELDS) ? *((const DWORD *)info->bmiColors + 2) : 0x001f;
break;
case 24:
case 32:
descr.rMask = (descr.compression == BI_BITFIELDS) ? *(const DWORD *)info->bmiColors : 0xff0000;
descr.gMask = (descr.compression == BI_BITFIELDS) ? *((const DWORD *)info->bmiColors + 1) : 0x00ff00;
descr.bMask = (descr.compression == BI_BITFIELDS) ? *((const DWORD *)info->bmiColors + 2) : 0x0000ff;
break;
}
descr.physDev = physDev;
descr.palentry = palette;
descr.bits = bits;
descr.image = physBitmap->image;
descr.infoWidth = width;
descr.lines = lines;
descr.depth = physBitmap->pixmap_depth;
descr.drawable = physBitmap->pixmap;
descr.gc = BITMAP_GC(physBitmap);
descr.width = dib.dsBm.bmWidth;
descr.height = dib.dsBm.bmHeight;
descr.xDest = 0;
descr.yDest = 0;
descr.xSrc = 0;
descr.sizeImage = core_header ? 0 : info->bmiHeader.biSizeImage;
if (descr.lines > 0)
{
descr.ySrc = (descr.height-1) - (startscan + (lines-1));
}
else
{
descr.ySrc = startscan;
}
#ifdef HAVE_LIBXXSHM
descr.useShm = (obj_size == sizeof(DIBSECTION)) && (physBitmap->shminfo.shmid != -1);
#else
descr.useShm = FALSE;
#endif
descr.dibpitch = (obj_size == sizeof(DIBSECTION)) ? dib.dsBm.bmWidthBytes
: (((descr.infoWidth * descr.infoBpp + 31) &~31) / 8);
X11DRV_DIB_Lock( physBitmap, DIB_Status_GdiMod );
X11DRV_DIB_GetImageBits( &descr );
X11DRV_DIB_Unlock( physBitmap, TRUE );
if(!core_header && info->bmiHeader.biSizeImage == 0) /* Fill in biSizeImage */
info->bmiHeader.biSizeImage = X11DRV_DIB_GetDIBImageBytes( descr.infoWidth,
descr.lines,
descr.infoBpp);
if (descr.compression == BI_BITFIELDS)
{
*(DWORD *)info->bmiColors = descr.rMask;
*((DWORD *)info->bmiColors + 1) = descr.gMask;
*((DWORD *)info->bmiColors + 2) = descr.bMask;
}
else if (!core_header)
{
/* if RLE or JPEG compression were supported,
* this line would be invalid. */
info->bmiHeader.biCompression = 0;
}
if(descr.colorMap != colorPtr)
HeapFree(GetProcessHeap(), 0, descr.colorMap);
return lines;
}
/***********************************************************************
* X11DRV_DIB_DoCopyDIBSection
*/
static void X11DRV_DIB_DoCopyDIBSection(X_PHYSBITMAP *physBitmap, BOOL toDIB,
void *colorMap, int nColorMap,
Drawable dest, GC gc,
DWORD xSrc, DWORD ySrc,
DWORD xDest, DWORD yDest,
DWORD width, DWORD height)
{
DIBSECTION dibSection;
X11DRV_DIB_IMAGEBITS_DESCR descr;
int identity[2] = {0,1};
if (!GetObjectW( physBitmap->hbitmap, sizeof(dibSection), &dibSection )) return;
descr.physDev = NULL;
descr.palentry = NULL;
descr.infoWidth = dibSection.dsBmih.biWidth;
descr.infoBpp = dibSection.dsBmih.biBitCount;
descr.lines = dibSection.dsBmih.biHeight;
descr.image = physBitmap->image;
descr.colorMap = colorMap;
descr.nColorMap = nColorMap;
descr.bits = dibSection.dsBm.bmBits;
descr.depth = physBitmap->pixmap_depth;
descr.compression = dibSection.dsBmih.biCompression;
if(descr.infoBpp == 1)
descr.colorMap = (void*)identity;
switch (descr.infoBpp)
{
case 1:
case 4:
case 8:
descr.rMask = descr.gMask = descr.bMask = 0;
break;
case 15:
case 16:
descr.rMask = (descr.compression == BI_BITFIELDS) ? dibSection.dsBitfields[0] : 0x7c00;
descr.gMask = (descr.compression == BI_BITFIELDS) ? dibSection.dsBitfields[1] : 0x03e0;
descr.bMask = (descr.compression == BI_BITFIELDS) ? dibSection.dsBitfields[2] : 0x001f;
break;
case 24:
case 32:
descr.rMask = (descr.compression == BI_BITFIELDS) ? dibSection.dsBitfields[0] : 0xff0000;
descr.gMask = (descr.compression == BI_BITFIELDS) ? dibSection.dsBitfields[1] : 0x00ff00;
descr.bMask = (descr.compression == BI_BITFIELDS) ? dibSection.dsBitfields[2] : 0x0000ff;
break;
}
/* Hack for now */
descr.drawable = dest;
descr.gc = gc;
descr.xSrc = xSrc;
descr.ySrc = ySrc;
descr.xDest = xDest;
descr.yDest = yDest;
descr.width = width;
descr.height = height;
descr.sizeImage = 0;
#ifdef HAVE_LIBXXSHM
descr.useShm = (physBitmap->shminfo.shmid != -1);
#else
descr.useShm = FALSE;
#endif
descr.dibpitch = 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(X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst,
DWORD xSrc, DWORD ySrc, DWORD xDest, DWORD yDest,
DWORD width, DWORD height)
{
DIBSECTION dib;
X_PHYSBITMAP *physBitmap;
unsigned int nColorMap;
int* x11ColorMap;
int freeColorMap;
TRACE("(%p,%p,%d,%d,%d,%d,%d,%d)\n", physDevSrc->hdc, physDevDst->hdc,
xSrc, ySrc, xDest, yDest, width, height);
/* this function is meant as an optimization for BitBlt,
* not to be called otherwise */
physBitmap = physDevSrc->bitmap;
if (!physBitmap || GetObjectW( physBitmap->hbitmap, sizeof(dib), &dib ) != sizeof(dib))
{
ERR("called for non-DIBSection!?\n");
return;
}
/* while BitBlt should already have made sure we only get
* positive values, we should check for oversize values */
if ((xSrc < dib.dsBm.bmWidth) &&
(ySrc < dib.dsBm.bmHeight)) {
if (xSrc + width > dib.dsBm.bmWidth)
width = dib.dsBm.bmWidth - xSrc;
if (ySrc + height > dib.dsBm.bmHeight)
height = dib.dsBm.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 (dib.dsBm.bmBitsPixel <= 8) {
HPALETTE hPalette = GetCurrentObject( physDevSrc->hdc, OBJ_PAL );
if (!hPalette || (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 */
x11ColorMap = physBitmap->colorMap;
nColorMap = physBitmap->nColorMap;
freeColorMap = FALSE;
} else {
const BITMAPINFO* info = (BITMAPINFO*)&dib.dsBmih;
int i;
nColorMap = X11DRV_DIB_GetColorCount(info);
x11ColorMap = HeapAlloc(GetProcessHeap(), 0, nColorMap * sizeof(int));
for (i = 0; i < nColorMap; i++)
x11ColorMap[i] = X11DRV_PALETTE_ToPhysical(physDevSrc, PALETTEINDEX(i));
freeColorMap = TRUE;
}
}
else
{
nColorMap = 0;
x11ColorMap = NULL;
freeColorMap = FALSE;
}
/* perform the copy */
X11DRV_DIB_DoCopyDIBSection(physBitmap, FALSE, x11ColorMap, nColorMap,
physDevDst->drawable, physDevDst->gc, xSrc, ySrc,
physDevDst->dc_rect.left + xDest, physDevDst->dc_rect.top + yDest,
width, height);
/* free color mapping */
if (freeColorMap)
HeapFree(GetProcessHeap(), 0, x11ColorMap);
}
}
/***********************************************************************
* X11DRV_DIB_DoUpdateDIBSection
*/
static void X11DRV_DIB_DoUpdateDIBSection(X_PHYSBITMAP *physBitmap, BOOL toDIB)
{
BITMAP bitmap;
GetObjectW( physBitmap->hbitmap, sizeof(bitmap), &bitmap );
X11DRV_DIB_DoCopyDIBSection(physBitmap, toDIB,
physBitmap->colorMap, physBitmap->nColorMap,
physBitmap->pixmap, BITMAP_GC(physBitmap),
0, 0, 0, 0, bitmap.bmWidth, bitmap.bmHeight);
}
/***********************************************************************
* X11DRV_DIB_FaultHandler
*/
static LONG CALLBACK X11DRV_DIB_FaultHandler( PEXCEPTION_POINTERS ep )
{
X_PHYSBITMAP *physBitmap = NULL;
BOOL found = FALSE;
BYTE *addr;
struct list *ptr;
const size_t pagemask = getpagesize() - 1;
if (ep->ExceptionRecord->ExceptionCode != EXCEPTION_ACCESS_VIOLATION)
return EXCEPTION_CONTINUE_SEARCH;
addr = (BYTE *)ep->ExceptionRecord->ExceptionInformation[1];
EnterCriticalSection(&dibs_cs);
LIST_FOR_EACH( ptr, &dibs_list )
{
physBitmap = LIST_ENTRY( ptr, X_PHYSBITMAP, entry );
if ((physBitmap->base <= addr) &&
(addr < physBitmap->base + ((physBitmap->size + pagemask) & ~pagemask)))
{
found = TRUE;
break;
}
}
LeaveCriticalSection(&dibs_cs);
if (!found) return EXCEPTION_CONTINUE_SEARCH;
if (addr >= physBitmap->base + physBitmap->size)
WARN( "%p: access to %p beyond the end of the DIB\n", physBitmap->hbitmap, addr );
X11DRV_DIB_Lock( physBitmap, DIB_Status_None );
if (ep->ExceptionRecord->ExceptionInformation[0] == EXCEPTION_WRITE_FAULT) {
/* the app tried to write the DIB bits */
X11DRV_DIB_Coerce( physBitmap, DIB_Status_AppMod);
} else {
/* the app tried to read the DIB bits */
X11DRV_DIB_Coerce( physBitmap, DIB_Status_InSync);
}
X11DRV_DIB_Unlock( physBitmap, TRUE );
return EXCEPTION_CONTINUE_EXECUTION;
}
/***********************************************************************
* X11DRV_DIB_Coerce
*/
static INT X11DRV_DIB_Coerce(X_PHYSBITMAP *physBitmap, INT req)
{
INT ret = DIB_Status_None;
if (!physBitmap->image) return ret; /* not a DIB section */
EnterCriticalSection(&physBitmap->lock);
ret = physBitmap->status;
switch (req) {
case DIB_Status_GdiMod:
/* GDI access - request to draw on pixmap */
switch (physBitmap->status)
{
default:
case DIB_Status_None:
physBitmap->p_status = DIB_Status_GdiMod;
X11DRV_DIB_DoUpdateDIBSection( physBitmap, FALSE );
break;
case DIB_Status_GdiMod:
TRACE("GdiMod requested in status GdiMod\n" );
physBitmap->p_status = DIB_Status_GdiMod;
break;
case DIB_Status_InSync:
TRACE("GdiMod requested in status InSync\n" );
X11DRV_DIB_DoProtectDIBSection( physBitmap, PAGE_NOACCESS );
physBitmap->status = DIB_Status_GdiMod;
physBitmap->p_status = DIB_Status_InSync;
break;
case DIB_Status_AppMod:
TRACE("GdiMod requested in status AppMod\n" );
/* make it readonly to avoid app changing data while we copy */
X11DRV_DIB_DoProtectDIBSection( physBitmap, PAGE_READONLY );
X11DRV_DIB_DoUpdateDIBSection( physBitmap, FALSE );
X11DRV_DIB_DoProtectDIBSection( physBitmap, PAGE_NOACCESS );
physBitmap->p_status = DIB_Status_AppMod;
physBitmap->status = DIB_Status_GdiMod;
break;
}
break;
case DIB_Status_InSync:
/* App access - request access to read DIB surface */
/* (typically called from signal handler) */
switch (physBitmap->status)
{
default:
case DIB_Status_None:
/* shouldn't happen from signal handler */
break;
case DIB_Status_GdiMod:
TRACE("InSync requested in status GdiMod\n" );
X11DRV_DIB_DoProtectDIBSection( physBitmap, PAGE_READWRITE );
X11DRV_DIB_DoUpdateDIBSection( physBitmap, TRUE );
X11DRV_DIB_DoProtectDIBSection( physBitmap, PAGE_READONLY );
physBitmap->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 (physBitmap->status)
{
default:
case DIB_Status_None:
/* shouldn't happen from signal handler */
break;
case DIB_Status_GdiMod:
TRACE("AppMod requested in status GdiMod\n" );
X11DRV_DIB_DoProtectDIBSection( physBitmap, PAGE_READWRITE );
X11DRV_DIB_DoUpdateDIBSection( physBitmap, TRUE );
physBitmap->status = DIB_Status_AppMod;
break;
case DIB_Status_InSync:
TRACE("AppMod requested in status InSync\n" );
X11DRV_DIB_DoProtectDIBSection( physBitmap, PAGE_READWRITE );
physBitmap->status = DIB_Status_AppMod;
break;
case DIB_Status_AppMod:
TRACE("AppMod requested in status AppMod\n" );
/* shouldn't happen from signal handler */
break;
}
break;
/* it is up to the caller to do the copy/conversion, probably
* using the return value to decide where to copy from */
}
LeaveCriticalSection(&physBitmap->lock);
return ret;
}
/***********************************************************************
* X11DRV_DIB_Lock
*/
static INT X11DRV_DIB_Lock(X_PHYSBITMAP *physBitmap, INT req)
{
INT ret = DIB_Status_None;
if (!physBitmap->image) return ret; /* not a DIB section */
TRACE("Locking %p from thread %04x\n", physBitmap->hbitmap, GetCurrentThreadId());
EnterCriticalSection(&physBitmap->lock);
ret = physBitmap->status;
if (req != DIB_Status_None)
X11DRV_DIB_Coerce(physBitmap, req);
return ret;
}
/***********************************************************************
* X11DRV_DIB_Unlock
*/
static void X11DRV_DIB_Unlock(X_PHYSBITMAP *physBitmap, BOOL commit)
{
if (!physBitmap->image) return; /* not a DIB section */
switch (physBitmap->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 (physBitmap->p_status)
{
case DIB_Status_GdiMod:
TRACE("Unlocking and syncing from GdiMod\n" );
X11DRV_DIB_DoUpdateDIBSection( physBitmap, TRUE );
break;
default:
TRACE("Unlocking without needing to sync\n" );
break;
}
}
else TRACE("Unlocking with no changes\n");
physBitmap->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 ((physBitmap->p_status == DIB_Status_InSync) ||
(physBitmap->p_status == DIB_Status_AppMod)) {
X11DRV_DIB_DoProtectDIBSection( physBitmap, PAGE_READONLY );
physBitmap->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;
}
LeaveCriticalSection(&physBitmap->lock);
TRACE("Unlocked %p\n", physBitmap->hbitmap);
}
/***********************************************************************
* X11DRV_CoerceDIBSection
*/
INT X11DRV_CoerceDIBSection(X11DRV_PDEVICE *physDev, INT req)
{
if (!physDev || !physDev->bitmap) return DIB_Status_None;
return X11DRV_DIB_Coerce(physDev->bitmap, req);
}
/***********************************************************************
* X11DRV_LockDIBSection
*/
INT X11DRV_LockDIBSection(X11DRV_PDEVICE *physDev, INT req)
{
if (!physDev || !physDev->bitmap) return DIB_Status_None;
return X11DRV_DIB_Lock(physDev->bitmap, req);
}
/***********************************************************************
* X11DRV_UnlockDIBSection
*/
void X11DRV_UnlockDIBSection(X11DRV_PDEVICE *physDev, BOOL commit)
{
if (!physDev || !physDev->bitmap) return;
X11DRV_DIB_Unlock(physDev->bitmap, commit);
}
#ifdef HAVE_LIBXXSHM
/***********************************************************************
* X11DRV_XShmErrorHandler
*
*/
static int XShmErrorHandler( Display *dpy, XErrorEvent *event, void *arg )
{
return 1; /* FIXME: should check event contents */
}
/***********************************************************************
* X11DRV_XShmCreateImage
*
*/
static XImage *X11DRV_XShmCreateImage( int width, int height, int bpp,
XShmSegmentInfo* shminfo)
{
XImage *image;
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 )
{
BOOL ok;
shminfo->readOnly = FALSE;
X11DRV_expect_error( gdi_display, XShmErrorHandler, NULL );
ok = (XShmAttach( gdi_display, shminfo ) != 0);
XSync( gdi_display, False );
if (X11DRV_check_error()) ok = FALSE;
if (ok)
{
shmctl(shminfo->shmid, IPC_RMID, 0);
return image; /* Success! */
}
/* An error occurred */
shmdt(shminfo->shmaddr);
}
shmctl(shminfo->shmid, IPC_RMID, 0);
shminfo->shmid = -1;
}
XFlush(gdi_display);
XDestroyImage(image);
image = NULL;
}
return image;
}
#endif /* HAVE_LIBXXSHM */
/***********************************************************************
* X11DRV_CreateDIBSection (X11DRV.@)
*/
HBITMAP X11DRV_CreateDIBSection( X11DRV_PDEVICE *physDev, HBITMAP hbitmap,
const BITMAPINFO *bmi, UINT usage )
{
X_PHYSBITMAP *physBitmap;
DIBSECTION dib;
if (!(physBitmap = X11DRV_init_phys_bitmap( hbitmap ))) return 0;
physBitmap->status = DIB_Status_None;
GetObjectW( hbitmap, sizeof(dib), &dib );
/* create color map */
if (dib.dsBm.bmBitsPixel <= 8)
{
physBitmap->colorMap = X11DRV_DIB_BuildColorMap( physDev,
usage, dib.dsBm.bmBitsPixel, bmi,
&physBitmap->nColorMap );
}
/* create pixmap and X image */
wine_tsx11_lock();
physBitmap->pixmap_depth = (dib.dsBm.bmBitsPixel == 1) ? 1 : screen_depth;
physBitmap->pixmap = XCreatePixmap( gdi_display, root_window, dib.dsBm.bmWidth,
dib.dsBm.bmHeight, physBitmap->pixmap_depth );
#ifdef HAVE_LIBXXSHM
physBitmap->shminfo.shmid = -1;
if (!XShmQueryExtension(gdi_display) ||
!(physBitmap->image = X11DRV_XShmCreateImage( dib.dsBm.bmWidth, dib.dsBm.bmHeight,
physBitmap->pixmap_depth, &physBitmap->shminfo )) )
#endif
physBitmap->image = X11DRV_DIB_CreateXImage( dib.dsBm.bmWidth, dib.dsBm.bmHeight,
physBitmap->pixmap_depth );
wine_tsx11_unlock();
if (!physBitmap->pixmap || !physBitmap->image) return 0;
/* install fault handler */
InitializeCriticalSection( &physBitmap->lock );
physBitmap->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": X_PHYSBITMAP.lock");
physBitmap->base = dib.dsBm.bmBits;
physBitmap->size = dib.dsBmih.biSizeImage;
physBitmap->status = DIB_Status_AppMod;
if (!dibs_handler)
dibs_handler = AddVectoredExceptionHandler( TRUE, X11DRV_DIB_FaultHandler );
EnterCriticalSection( &dibs_cs );
list_add_head( &dibs_list, &physBitmap->entry );
LeaveCriticalSection( &dibs_cs );
X11DRV_DIB_DoProtectDIBSection( physBitmap, PAGE_READWRITE );
return hbitmap;
}
/***********************************************************************
* X11DRV_DIB_DeleteDIBSection
*/
void X11DRV_DIB_DeleteDIBSection(X_PHYSBITMAP *physBitmap, DIBSECTION *dib)
{
BOOL last;
EnterCriticalSection( &dibs_cs );
list_remove( &physBitmap->entry );
last = list_empty( &dibs_list );
LeaveCriticalSection( &dibs_cs );
if (last)
{
RemoveVectoredExceptionHandler( dibs_handler );
dibs_handler = NULL;
}
if (dib->dshSection)
X11DRV_DIB_Coerce(physBitmap, DIB_Status_InSync);
if (physBitmap->image)
{
wine_tsx11_lock();
#ifdef HAVE_LIBXXSHM
if (physBitmap->shminfo.shmid != -1)
{
XShmDetach( gdi_display, &(physBitmap->shminfo) );
XDestroyImage( physBitmap->image );
shmdt( physBitmap->shminfo.shmaddr );
physBitmap->shminfo.shmid = -1;
}
else
#endif
XDestroyImage( physBitmap->image );
wine_tsx11_unlock();
}
HeapFree(GetProcessHeap(), 0, physBitmap->colorMap);
physBitmap->lock.DebugInfo->Spare[0] = 0;
DeleteCriticalSection(&physBitmap->lock);
}
/***********************************************************************
* SetDIBColorTable (X11DRV.@)
*/
UINT X11DRV_SetDIBColorTable( X11DRV_PDEVICE *physDev, UINT start, UINT count, const RGBQUAD *colors )
{
DIBSECTION dib;
UINT ret = 0;
X_PHYSBITMAP *physBitmap = physDev->bitmap;
if (!physBitmap) return 0;
GetObjectW( physBitmap->hbitmap, sizeof(dib), &dib );
if (physBitmap->colorMap && start < physBitmap->nColorMap) {
UINT end = count + start;
if (end > physBitmap->nColorMap) end = physBitmap->nColorMap;
/*
* Changing color table might change the mapping between
* DIB colors and X11 colors and thus alter the visible state
* of the bitmap object.
*/
/*
* FIXME we need to recalculate the pen, brush, text and bkgnd pixels here,
* at least for a 1 bpp dibsection
*/
X11DRV_DIB_Lock( physBitmap, DIB_Status_AppMod );
X11DRV_DIB_GenColorMap( physDev, physBitmap->colorMap, DIB_RGB_COLORS,
dib.dsBm.bmBitsPixel,
TRUE, colors, start, end );
X11DRV_DIB_Unlock( physBitmap, TRUE );
ret = end - start;
}
return ret;
}
/***********************************************************************
* X11DRV_DIB_CreateDIBFromBitmap
*
* Allocates a packed DIB and copies the bitmap data into it.
*/
HGLOBAL X11DRV_DIB_CreateDIBFromBitmap(HDC hdc, HBITMAP hBmp)
{
BITMAP bmp;
HGLOBAL hPackedDIB;
LPBYTE pPackedDIB;
LPBITMAPINFOHEADER pbmiHeader;
unsigned int cDataSize, cPackedSize, OffsetBits;
int nLinesCopied;
if (!GetObjectW( hBmp, sizeof(bmp), &bmp )) return 0;
/*
* A packed DIB contains a BITMAPINFO structure followed immediately by
* an optional color palette and the pixel data.
*/
/* Calculate the size of the packed DIB */
cDataSize = X11DRV_DIB_GetDIBWidthBytes( bmp.bmWidth, bmp.bmBitsPixel ) * abs( bmp.bmHeight );
cPackedSize = sizeof(BITMAPINFOHEADER)
+ ( (bmp.bmBitsPixel <= 8) ? (sizeof(RGBQUAD) * (1 << bmp.bmBitsPixel)) : 0 )
+ cDataSize;
/* Get the offset to the bits */
OffsetBits = cPackedSize - cDataSize;
/* Allocate the packed DIB */
TRACE("\tAllocating packed DIB of size %d\n", cPackedSize);
hPackedDIB = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE /*| GMEM_ZEROINIT*/,
cPackedSize );
if ( !hPackedDIB )
{
WARN("Could not allocate packed DIB!\n");
return 0;
}
/* A packed DIB starts with a BITMAPINFOHEADER */
pPackedDIB = GlobalLock(hPackedDIB);
pbmiHeader = (LPBITMAPINFOHEADER)pPackedDIB;
/* Init the BITMAPINFOHEADER */
pbmiHeader->biSize = sizeof(BITMAPINFOHEADER);
pbmiHeader->biWidth = bmp.bmWidth;
pbmiHeader->biHeight = bmp.bmHeight;
pbmiHeader->biPlanes = 1;
pbmiHeader->biBitCount = bmp.bmBitsPixel;
pbmiHeader->biCompression = BI_RGB;
pbmiHeader->biSizeImage = 0;
pbmiHeader->biXPelsPerMeter = pbmiHeader->biYPelsPerMeter = 0;
pbmiHeader->biClrUsed = 0;
pbmiHeader->biClrImportant = 0;
/* Retrieve the DIB bits from the bitmap and fill in the
* DIB color table if present */
nLinesCopied = GetDIBits(hdc, /* Handle to device context */
hBmp, /* Handle to bitmap */
0, /* First scan line to set in dest bitmap */
bmp.bmHeight, /* Number of scan lines to copy */
pPackedDIB + OffsetBits, /* [out] Address of array for bitmap bits */
(LPBITMAPINFO) pbmiHeader, /* [out] Address of BITMAPINFO structure */
0); /* RGB or palette index */
GlobalUnlock(hPackedDIB);
/* Cleanup if GetDIBits failed */
if (nLinesCopied != bmp.bmHeight)
{
TRACE("\tGetDIBits returned %d. Actual lines=%d\n", nLinesCopied, bmp.bmHeight);
GlobalFree(hPackedDIB);
hPackedDIB = 0;
}
return hPackedDIB;
}
/**************************************************************************
* X11DRV_DIB_CreateDIBFromPixmap
*
* Allocates a packed DIB and copies the Pixmap data into it.
* The Pixmap passed in is deleted after the conversion.
*/
HGLOBAL X11DRV_DIB_CreateDIBFromPixmap(Pixmap pixmap, HDC hdc)
{
HDC hdcMem;
X_PHYSBITMAP *physBitmap;
HBITMAP hBmp = 0, old;
HGLOBAL hPackedDIB = 0;
Window root;
int x,y; /* Unused */
unsigned border_width; /* Unused */
unsigned int depth, width, height;
/* Get the Pixmap dimensions and bit depth */
wine_tsx11_lock();
if (!XGetGeometry(gdi_display, pixmap, &root, &x, &y, &width, &height,
&border_width, &depth)) depth = 0;
wine_tsx11_unlock();
if (!depth) return 0;
TRACE("\tPixmap properties: width=%d, height=%d, depth=%d\n",
width, height, depth);
/*
* Create an HBITMAP with the same dimensions and BPP as the pixmap,
* and make it a container for the pixmap passed.
*/
if (!(hBmp = CreateBitmap( width, height, 1, depth_to_bpp(depth), NULL ))) return 0;
/* force bitmap to be owned by a screen DC */
hdcMem = CreateCompatibleDC( hdc );
old = SelectObject( hdcMem, hBmp );
physBitmap = X11DRV_get_phys_bitmap( hBmp );
wine_tsx11_lock();
if (physBitmap->pixmap) XFreePixmap( gdi_display, physBitmap->pixmap );
physBitmap->pixmap = pixmap;
wine_tsx11_unlock();
SelectObject( hdcMem, old );
DeleteDC( hdcMem );
/*
* 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 = X11DRV_DIB_CreateDIBFromBitmap(hdc, hBmp);
/* We can now get rid of the HBITMAP wrapper we created earlier.
* Note: Simply calling DeleteObject will free the embedded Pixmap as well.
*/
DeleteObject(hBmp);
TRACE("\tReturning packed DIB %p\n", hPackedDIB);
return hPackedDIB;
}
/**************************************************************************
* X11DRV_DIB_CreatePixmapFromDIB
*
* Creates a Pixmap from a packed DIB
*/
Pixmap X11DRV_DIB_CreatePixmapFromDIB( HGLOBAL hPackedDIB, HDC hdc )
{
Pixmap pixmap;
X_PHYSBITMAP *physBitmap;
HBITMAP hBmp;
LPBITMAPINFO pbmi;
/* Create a DDB from the DIB */
pbmi = GlobalLock(hPackedDIB);
hBmp = CreateDIBitmap(hdc, &pbmi->bmiHeader, CBM_INIT,
(LPBYTE)pbmi + X11DRV_DIB_BitmapInfoSize( pbmi, DIB_RGB_COLORS ),
pbmi, DIB_RGB_COLORS);
GlobalUnlock(hPackedDIB);
/* clear the physBitmap so that we can steal its pixmap */
physBitmap = X11DRV_get_phys_bitmap( hBmp );
pixmap = physBitmap->pixmap;
physBitmap->pixmap = 0;
/* Delete the DDB we created earlier now that we have stolen its pixmap */
DeleteObject(hBmp);
TRACE("Returning Pixmap %ld\n", pixmap);
return pixmap;
}