From b55746ab62739fc1e4c0d4a15484e0e8337bab75 Mon Sep 17 00:00:00 2001 From: Huw Davies Date: Thu, 2 Mar 2006 12:13:28 +0000 Subject: [PATCH] gdi: Better support for 1bpp dib sections. --- dlls/gdi/tests/bitmap.c | 216 ++++++++++++++++++++++++++++++++++++++++ dlls/x11drv/dib.c | 52 ++++++++-- dlls/x11drv/palette.c | 28 +++++- dlls/x11drv/x11drv.h | 3 - 4 files changed, 281 insertions(+), 18 deletions(-) diff --git a/dlls/gdi/tests/bitmap.c b/dlls/gdi/tests/bitmap.c index 5eeda35e9f0..7f2a59c7ade 100644 --- a/dlls/gdi/tests/bitmap.c +++ b/dlls/gdi/tests/bitmap.c @@ -342,6 +342,27 @@ static void test_dibsections(void) SelectObject(hdcmem, oldbm); DeleteObject(hdib); + pbmi->bmiColors[0].rgbRed = 0xff; + pbmi->bmiColors[0].rgbGreen = 0xff; + pbmi->bmiColors[0].rgbBlue = 0xff; + pbmi->bmiColors[1].rgbRed = 0; + pbmi->bmiColors[1].rgbGreen = 0; + pbmi->bmiColors[1].rgbBlue = 0; + + hdib = CreateDIBSection(hdc, pbmi, DIB_RGB_COLORS, (void**)&bits, NULL, 0); + ok(hdib != NULL, "CreateDIBSection failed\n"); + oldbm = SelectObject(hdcmem, hdib); + + ret = GetDIBColorTable(hdcmem, 0, 2, rgb); + ok(ret == 2, "GetDIBColorTable returned %d\n", ret); + ok(!memcmp(rgb, pbmi->bmiColors, 2 * sizeof(RGBQUAD)), + "GetDIBColorTable returns table 0: r%02x g%02x b%02x res%02x 1: r%02x g%02x b%02x res%02x\n", + rgb[0].rgbRed, rgb[0].rgbGreen, rgb[0].rgbBlue, rgb[0].rgbReserved, + rgb[1].rgbRed, rgb[1].rgbGreen, rgb[1].rgbBlue, rgb[1].rgbReserved); + + SelectObject(hdcmem, oldbm); + DeleteObject(hdib); + pbmi->bmiHeader.biBitCount = 4; for (i = 0; i < 16; i++) { pbmi->bmiColors[i].rgbRed = i; @@ -528,6 +549,200 @@ static void test_dibsections(void) ReleaseDC(0, hdc); } +void test_mono_dibsection(void) +{ + HDC hdc, memdc; + HBITMAP old_bm, mono_ds; + char bmibuf[sizeof(BITMAPINFO) + 256 * sizeof(RGBQUAD)]; + BITMAPINFO *pbmi = (BITMAPINFO *)bmibuf; + BYTE bits[10 * 4]; + BYTE *ds_bits; + int num; + + hdc = GetDC(0); + + memdc = CreateCompatibleDC(hdc); + + memset(pbmi, 0, sizeof(bmibuf)); + pbmi->bmiHeader.biSize = sizeof(pbmi->bmiHeader); + pbmi->bmiHeader.biHeight = 10; + pbmi->bmiHeader.biWidth = 10; + pbmi->bmiHeader.biBitCount = 1; + pbmi->bmiHeader.biPlanes = 1; + pbmi->bmiHeader.biCompression = BI_RGB; + pbmi->bmiColors[0].rgbRed = 0xff; + pbmi->bmiColors[0].rgbGreen = 0xff; + pbmi->bmiColors[0].rgbBlue = 0xff; + pbmi->bmiColors[1].rgbRed = 0x0; + pbmi->bmiColors[1].rgbGreen = 0x0; + pbmi->bmiColors[1].rgbBlue = 0x0; + + /* + * First dib section is 'inverted' ie color[0] is white, color[1] is black + */ + + mono_ds = CreateDIBSection(hdc, pbmi, DIB_RGB_COLORS, (void**)&ds_bits, NULL, 0); + ok(mono_ds != NULL, "CreateDIBSection rets NULL\n"); + old_bm = SelectObject(memdc, mono_ds); + + /* black border, white interior */ + Rectangle(memdc, 0, 0, 10, 10); + ok(ds_bits[0] == 0xff, "out_bits %02x\n", ds_bits[0]); + ok(ds_bits[4] == 0x80, "out_bits %02x\n", ds_bits[4]); + + /* SetDIBitsToDevice with an inverted bmi -> inverted dib section */ + + memset(bits, 0, sizeof(bits)); + bits[0] = 0xaa; + + SetDIBitsToDevice(memdc, 0, 0, 10, 10, 0, 0, 0, 10, bits, pbmi, DIB_RGB_COLORS); + ok(ds_bits[0] == 0xaa, "out_bits %02x\n", ds_bits[0]); + + /* SetDIBitsToDevice with a normal bmi -> inverted dib section */ + + pbmi->bmiColors[0].rgbRed = 0x0; + pbmi->bmiColors[0].rgbGreen = 0x0; + pbmi->bmiColors[0].rgbBlue = 0x0; + pbmi->bmiColors[1].rgbRed = 0xff; + pbmi->bmiColors[1].rgbGreen = 0xff; + pbmi->bmiColors[1].rgbBlue = 0xff; + + SetDIBitsToDevice(memdc, 0, 0, 10, 10, 0, 0, 0, 10, bits, pbmi, DIB_RGB_COLORS); + ok(ds_bits[0] == 0x55, "out_bits %02x\n", ds_bits[0]); + + SelectObject(memdc, old_bm); + DeleteObject(mono_ds); + + /* + * Next dib section is 'normal' ie color[0] is black, color[1] is white + */ + + pbmi->bmiColors[0].rgbRed = 0x0; + pbmi->bmiColors[0].rgbGreen = 0x0; + pbmi->bmiColors[0].rgbBlue = 0x0; + pbmi->bmiColors[1].rgbRed = 0xff; + pbmi->bmiColors[1].rgbGreen = 0xff; + pbmi->bmiColors[1].rgbBlue = 0xff; + + mono_ds = CreateDIBSection(hdc, pbmi, DIB_RGB_COLORS, (void**)&ds_bits, NULL, 0); + ok(mono_ds != NULL, "CreateDIBSection rets NULL\n"); + old_bm = SelectObject(memdc, mono_ds); + + /* black border, white interior */ + Rectangle(memdc, 0, 0, 10, 10); + ok(ds_bits[0] == 0x00, "out_bits %02x\n", ds_bits[0]); + ok(ds_bits[4] == 0x7f, "out_bits %02x\n", ds_bits[4]); + + /* SetDIBitsToDevice with a normal bmi -> normal dib section */ + + SetDIBitsToDevice(memdc, 0, 0, 10, 10, 0, 0, 0, 10, bits, pbmi, DIB_RGB_COLORS); + ok(ds_bits[0] == 0xaa, "out_bits %02x\n", ds_bits[0]); + + /* SetDIBitsToDevice with a inverted bmi -> normal dib section */ + + pbmi->bmiColors[0].rgbRed = 0xff; + pbmi->bmiColors[0].rgbGreen = 0xff; + pbmi->bmiColors[0].rgbBlue = 0xff; + pbmi->bmiColors[1].rgbRed = 0x0; + pbmi->bmiColors[1].rgbGreen = 0x0; + pbmi->bmiColors[1].rgbBlue = 0x0; + + SetDIBitsToDevice(memdc, 0, 0, 10, 10, 0, 0, 0, 10, bits, pbmi, DIB_RGB_COLORS); + ok(ds_bits[0] == 0x55, "out_bits %02x\n", ds_bits[0]); + + /* + * Take that 'normal' dibsection and change its colour table to an 'inverted' one + */ + + pbmi->bmiColors[0].rgbRed = 0xff; + pbmi->bmiColors[0].rgbGreen = 0xff; + pbmi->bmiColors[0].rgbBlue = 0xff; + pbmi->bmiColors[1].rgbRed = 0x0; + pbmi->bmiColors[1].rgbGreen = 0x0; + pbmi->bmiColors[1].rgbBlue = 0x0; + num = SetDIBColorTable(memdc, 0, 2, pbmi->bmiColors); + ok(num == 2, "num = %d\n", num); + + /* black border, white interior */ + Rectangle(memdc, 0, 0, 10, 10); +todo_wine { + ok(ds_bits[0] == 0xff, "out_bits %02x\n", ds_bits[0]); + ok(ds_bits[4] == 0x80, "out_bits %02x\n", ds_bits[4]); + } + /* SetDIBitsToDevice with an inverted bmi -> inverted dib section */ + + memset(bits, 0, sizeof(bits)); + bits[0] = 0xaa; + + SetDIBitsToDevice(memdc, 0, 0, 10, 10, 0, 0, 0, 10, bits, pbmi, DIB_RGB_COLORS); + ok(ds_bits[0] == 0xaa, "out_bits %02x\n", ds_bits[0]); + + /* SetDIBitsToDevice with a normal bmi -> inverted dib section */ + + pbmi->bmiColors[0].rgbRed = 0x0; + pbmi->bmiColors[0].rgbGreen = 0x0; + pbmi->bmiColors[0].rgbBlue = 0x0; + pbmi->bmiColors[1].rgbRed = 0xff; + pbmi->bmiColors[1].rgbGreen = 0xff; + pbmi->bmiColors[1].rgbBlue = 0xff; + + SetDIBitsToDevice(memdc, 0, 0, 10, 10, 0, 0, 0, 10, bits, pbmi, DIB_RGB_COLORS); + ok(ds_bits[0] == 0x55, "out_bits %02x\n", ds_bits[0]); + + SelectObject(memdc, old_bm); + DeleteObject(mono_ds); + + /* + * Now a dib section with a strange colour map just for fun. This behaves just like an inverted one. + */ + + pbmi->bmiColors[0].rgbRed = 0xff; + pbmi->bmiColors[0].rgbGreen = 0x0; + pbmi->bmiColors[0].rgbBlue = 0x0; + pbmi->bmiColors[1].rgbRed = 0xfe; + pbmi->bmiColors[1].rgbGreen = 0x0; + pbmi->bmiColors[1].rgbBlue = 0x0; + + mono_ds = CreateDIBSection(hdc, pbmi, DIB_RGB_COLORS, (void**)&ds_bits, NULL, 0); + ok(mono_ds != NULL, "CreateDIBSection rets NULL\n"); + old_bm = SelectObject(memdc, mono_ds); + + /* black border, white interior */ + Rectangle(memdc, 0, 0, 10, 10); + ok(ds_bits[0] == 0xff, "out_bits %02x\n", ds_bits[0]); + ok(ds_bits[4] == 0x80, "out_bits %02x\n", ds_bits[4]); + + /* SetDIBitsToDevice with a normal bmi -> inverted dib section */ + + pbmi->bmiColors[0].rgbRed = 0x0; + pbmi->bmiColors[0].rgbGreen = 0x0; + pbmi->bmiColors[0].rgbBlue = 0x0; + pbmi->bmiColors[1].rgbRed = 0xff; + pbmi->bmiColors[1].rgbGreen = 0xff; + pbmi->bmiColors[1].rgbBlue = 0xff; + + SetDIBitsToDevice(memdc, 0, 0, 10, 10, 0, 0, 0, 10, bits, pbmi, DIB_RGB_COLORS); + ok(ds_bits[0] == 0x55, "out_bits %02x\n", ds_bits[0]); + + /* SetDIBitsToDevice with a inverted bmi -> inverted dib section */ + + pbmi->bmiColors[0].rgbRed = 0xff; + pbmi->bmiColors[0].rgbGreen = 0xff; + pbmi->bmiColors[0].rgbBlue = 0xff; + pbmi->bmiColors[1].rgbRed = 0x0; + pbmi->bmiColors[1].rgbGreen = 0x0; + pbmi->bmiColors[1].rgbBlue = 0x0; + + SetDIBitsToDevice(memdc, 0, 0, 10, 10, 0, 0, 0, 10, bits, pbmi, DIB_RGB_COLORS); + ok(ds_bits[0] == 0xaa, "out_bits %02x\n", ds_bits[0]); + + SelectObject(memdc, old_bm); + DeleteObject(mono_ds); + + DeleteDC(memdc); + ReleaseDC(0, hdc); +} + START_TEST(bitmap) { HWND hWnd; @@ -541,4 +756,5 @@ START_TEST(bitmap) test_createdibitmap(); test_dibsections(); + test_mono_dibsection(); } diff --git a/dlls/x11drv/dib.c b/dlls/x11drv/dib.c index f9321e6f360..5904f0ad458 100644 --- a/dlls/x11drv/dib.c +++ b/dlls/x11drv/dib.c @@ -272,6 +272,12 @@ static int DIB_GetBitmapInfo( const BITMAPINFOHEADER *header, LONG *width, } +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 * @@ -291,9 +297,19 @@ static int *X11DRV_DIB_GenColorMap( X11DRV_PDEVICE *physDev, int *colorMapping, const RGBQUAD * rgb = (const RGBQUAD *)colorPtr; if (depth == 1) /* Monochrome */ - for (i = start; i < end; i++, rgb++) - colorMapping[i] = (rgb->rgbRed + rgb->rgbGreen + - rgb->rgbBlue > 255*3/2); + { + BOOL invert = FALSE; + if(physDev && physDev->bitmap && physDev->bitmap->colorTable) + { + if(!colour_is_brighter(physDev->bitmap->colorTable[1], physDev->bitmap->colorTable[0])) + invert = TRUE; + } + 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( physDev, RGB(rgb->rgbRed, @@ -305,9 +321,19 @@ static int *X11DRV_DIB_GenColorMap( X11DRV_PDEVICE *physDev, int *colorMapping, const RGBTRIPLE * rgb = (const RGBTRIPLE *)colorPtr; if (depth == 1) /* Monochrome */ + { + BOOL invert = FALSE; + if(physDev && physDev->bitmap && physDev->bitmap->colorTable) + { + if(!colour_is_brighter(physDev->bitmap->colorTable[1], physDev->bitmap->colorTable[0])) + invert = TRUE; + } for (i = start; i < end; i++, rgb++) - colorMapping[i] = (rgb->rgbtRed + rgb->rgbtGreen + - rgb->rgbtBlue > 255*3/2); + 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( physDev, RGB(rgb->rgbtRed, @@ -337,8 +363,8 @@ static int *X11DRV_DIB_GenColorMap( X11DRV_PDEVICE *physDev, int *colorMapping, * Build the color map from the bitmap palette. Should not be called * for a >8-bit deep bitmap. */ -int *X11DRV_DIB_BuildColorMap( X11DRV_PDEVICE *physDev, WORD coloruse, WORD depth, - const BITMAPINFO *info, int *nColors ) +static int *X11DRV_DIB_BuildColorMap( X11DRV_PDEVICE *physDev, WORD coloruse, WORD depth, + const BITMAPINFO *info, int *nColors ) { unsigned int colors; BOOL isInfo; @@ -3852,7 +3878,7 @@ INT X11DRV_SetDIBitsToDevice( X11DRV_PDEVICE *physDev, INT xDest, INT yDest, DWO case 4: case 8: descr.colorMap = (RGBQUAD *)X11DRV_DIB_BuildColorMap( - coloruse == DIB_PAL_COLORS ? physDev : NULL, coloruse, + physDev, coloruse, physDev->depth, info, &descr.nColorMap ); if (!descr.colorMap) return 0; descr.rMask = descr.gMask = descr.bMask = 0; @@ -3938,7 +3964,7 @@ INT X11DRV_SetDIBits( X11DRV_PDEVICE *physDev, HBITMAP hbitmap, UINT startscan, case 4: case 8: descr.colorMap = (RGBQUAD *)X11DRV_DIB_BuildColorMap( - coloruse == DIB_PAL_COLORS ? descr.physDev : NULL, coloruse, + descr.physDev, coloruse, physBitmap->pixmap_depth, info, &descr.nColorMap ); if (!descr.colorMap) return 0; @@ -4637,10 +4663,10 @@ HBITMAP X11DRV_CreateDIBSection( X11DRV_PDEVICE *physDev, HBITMAP hbitmap, /* create color map */ if (dib.dsBm.bmBitsPixel <= 8) { - physBitmap->colorMap = X11DRV_DIB_BuildColorMap( usage == DIB_PAL_COLORS ? physDev : NULL, + physBitmap->colorTable = X11DRV_DIB_BuildColorTable( physDev, usage, dib.dsBm.bmBitsPixel, bmi ); + physBitmap->colorMap = X11DRV_DIB_BuildColorMap( physDev, usage, dib.dsBm.bmBitsPixel, bmi, &physBitmap->nColorMap ); - physBitmap->colorTable = X11DRV_DIB_BuildColorTable( physDev, usage, dib.dsBm.bmBitsPixel, bmi ); } /* create pixmap and X image */ @@ -4740,6 +4766,10 @@ UINT X11DRV_SetDIBColorTable( X11DRV_PDEVICE *physDev, UINT start, UINT count, c * 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, FALSE ); memcpy(physBitmap->colorTable + start, colors, (end - start) * sizeof(RGBQUAD)); X11DRV_DIB_GenColorMap( physDev, physBitmap->colorMap, DIB_RGB_COLORS, diff --git a/dlls/x11drv/palette.c b/dlls/x11drv/palette.c index 56ae55dc314..0c6ad12147f 100644 --- a/dlls/x11drv/palette.c +++ b/dlls/x11drv/palette.c @@ -808,6 +808,12 @@ static int X11DRV_SysPaletteLookupPixel( COLORREF col, BOOL skipReserved ) return best; } + +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_PALETTE_ToPhysical @@ -870,9 +876,16 @@ int X11DRV_PALETTE_ToPhysical( X11DRV_PDEVICE *physDev, COLORREF color ) case 0: /* RGB */ if (physDev && (physDev->depth == 1) ) { + int white = 1; + GDI_ReleaseObj( hPal ); + if (physDev->bitmap && physDev->bitmap->colorTable) + { + if(!colour_is_brighter(physDev->bitmap->colorTable[1], physDev->bitmap->colorTable[0])) + white = 0; + } return (((color >> 16) & 0xff) + - ((color >> 8) & 0xff) + (color & 0xff) > 255*3/2) ? 1 : 0; + ((color >> 8) & 0xff) + (color & 0xff) > 255*3/2) ? white : 1 - white; } } @@ -923,9 +936,16 @@ int X11DRV_PALETTE_ToPhysical( X11DRV_PDEVICE *physDev, COLORREF color ) case 0: /* RGB */ if (physDev && (physDev->depth == 1) ) { - GDI_ReleaseObj( hPal ); - return (((color >> 16) & 0xff) + - ((color >> 8) & 0xff) + (color & 0xff) > 255*3/2) ? 1 : 0; + int white = 1; + + GDI_ReleaseObj( hPal ); + if (physDev->bitmap && physDev->bitmap->colorTable) + { + if(!colour_is_brighter(physDev->bitmap->colorTable[1], physDev->bitmap->colorTable[0])) + white = 0; + } + return (((color >> 16) & 0xff) + + ((color >> 8) & 0xff) + (color & 0xff) > 255*3/2) ? white : 1 - white; } index = X11DRV_SysPaletteLookupPixel( color, FALSE); diff --git a/dlls/x11drv/x11drv.h b/dlls/x11drv/x11drv.h index 0339fad7866..98c0e93dda9 100644 --- a/dlls/x11drv/x11drv.h +++ b/dlls/x11drv/x11drv.h @@ -421,9 +421,6 @@ typedef struct { extern const dib_conversions dib_normal, dib_src_byteswap, dib_dst_byteswap; extern INT X11DRV_DIB_MaskToShift(DWORD mask); -extern int *X11DRV_DIB_BuildColorMap( X11DRV_PDEVICE *physDev, WORD coloruse, - WORD depth, const BITMAPINFO *info, - int *nColors ); extern INT X11DRV_CoerceDIBSection(X11DRV_PDEVICE *physDev,INT,BOOL); extern INT X11DRV_LockDIBSection(X11DRV_PDEVICE *physDev,INT,BOOL); extern void X11DRV_UnlockDIBSection(X11DRV_PDEVICE *physDev,BOOL);