diff --git a/dlls/gdi32/Makefile.in b/dlls/gdi32/Makefile.in index 6a047429e78..e27a12aff15 100644 --- a/dlls/gdi32/Makefile.in +++ b/dlls/gdi32/Makefile.in @@ -14,6 +14,7 @@ C_SRCS = \ clipping.c \ dc.c \ dib.c \ + dibdrv/bitblt.c \ dibdrv/dc.c \ dibdrv/graphics.c \ dibdrv/objects.c \ diff --git a/dlls/gdi32/dibdrv/bitblt.c b/dlls/gdi32/dibdrv/bitblt.c new file mode 100644 index 00000000000..9e6c74f10f0 --- /dev/null +++ b/dlls/gdi32/dibdrv/bitblt.c @@ -0,0 +1,280 @@ +/* + * DIB driver blitting + * + * Copyright 2011 Huw Davies + * + * 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 + +#include "gdi_private.h" +#include "dibdrv.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(dib); + +static void set_color_info( const dib_info *dib, BITMAPINFO *info ) +{ + DWORD *masks = (DWORD *)info->bmiColors; + + info->bmiHeader.biCompression = BI_RGB; + info->bmiHeader.biClrUsed = 0; + + switch (info->bmiHeader.biBitCount) + { + case 1: + case 4: + case 8: + if (dib->color_table) + { + info->bmiHeader.biClrUsed = min( dib->color_table_size, 1 << dib->bit_count ); + memcpy( info->bmiColors, dib->color_table, + info->bmiHeader.biClrUsed * sizeof(RGBQUAD) ); + } + break; + case 16: + masks[0] = dib->red_mask; + masks[1] = dib->green_mask; + masks[2] = dib->blue_mask; + info->bmiHeader.biCompression = BI_BITFIELDS; + break; + case 32: + if (dib->funcs != &funcs_8888) + { + masks[0] = dib->red_mask; + masks[1] = dib->green_mask; + masks[2] = dib->blue_mask; + info->bmiHeader.biCompression = BI_BITFIELDS; + } + break; + } +} + +/*********************************************************************** + * dibdrv_GetImage + */ +DWORD dibdrv_GetImage( PHYSDEV dev, HBITMAP hbitmap, BITMAPINFO *info, + struct gdi_image_bits *bits, struct bitblt_coords *src ) +{ + DWORD ret = ERROR_SUCCESS; + dib_info *dib, stand_alone; + + TRACE( "%p %p %p\n", dev, hbitmap, info ); + + info->bmiHeader.biSize = sizeof(info->bmiHeader); + info->bmiHeader.biPlanes = 1; + info->bmiHeader.biCompression = BI_RGB; + info->bmiHeader.biXPelsPerMeter = 0; + info->bmiHeader.biYPelsPerMeter = 0; + info->bmiHeader.biClrUsed = 0; + info->bmiHeader.biClrImportant = 0; + + if (hbitmap) + { + BITMAPOBJ *bmp = GDI_GetObjPtr( hbitmap, OBJ_BITMAP ); + + if (!bmp) return ERROR_INVALID_HANDLE; + assert(bmp->dib); + + if (!init_dib_info( &stand_alone, &bmp->dib->dsBmih, bmp->dib->dsBitfields, + bmp->color_table, bmp->nb_colors, bmp->dib->dsBm.bmBits, 0 )) + { + ret = ERROR_BAD_FORMAT; + goto done; + } + dib = &stand_alone; + } + else + { + dibdrv_physdev *pdev = get_dibdrv_pdev(dev); + dib = &pdev->dib; + } + + info->bmiHeader.biWidth = dib->width; + info->bmiHeader.biHeight = dib->stride > 0 ? -dib->height : dib->height; + info->bmiHeader.biBitCount = dib->bit_count; + info->bmiHeader.biSizeImage = dib->height * abs( dib->stride ); + + set_color_info( dib, info ); + + if (bits) + { + bits->ptr = dib->bits.ptr; + if (dib->stride < 0) + bits->ptr = (char *)bits->ptr + (dib->height - 1) * dib->stride; + bits->is_copy = FALSE; + bits->free = NULL; + } + +done: + if (hbitmap) GDI_ReleaseObj( hbitmap ); + return ret; +} + +static BOOL matching_color_info( const dib_info *dib, const BITMAPINFO *info ) +{ + switch (info->bmiHeader.biBitCount) + { + case 1: + case 4: + case 8: + { + RGBQUAD *color_table = (RGBQUAD *)((char *)info + info->bmiHeader.biSize); + if (dib->color_table_size != get_dib_num_of_colors( info )) return FALSE; + return !memcmp( color_table, dib->color_table, dib->color_table_size * sizeof(RGBQUAD) ); + } + + case 16: + { + DWORD *masks = (DWORD *)info->bmiColors; + if (info->bmiHeader.biCompression == BI_RGB) return dib->funcs == &funcs_555; + if (info->bmiHeader.biCompression == BI_BITFIELDS) + return masks[0] == dib->red_mask && masks[1] == dib->green_mask && masks[2] == dib->blue_mask; + break; + } + + case 24: + return TRUE; + + case 32: + { + DWORD *masks = (DWORD *)info->bmiColors; + if (info->bmiHeader.biCompression == BI_RGB) return dib->funcs == &funcs_8888; + if (info->bmiHeader.biCompression == BI_BITFIELDS) + return masks[0] == dib->red_mask && masks[1] == dib->green_mask && masks[2] == dib->blue_mask; + break; + } + + } + + return FALSE; +} + +static inline BOOL rop_uses_pat(DWORD rop) +{ + return ((rop >> 4) & 0x0f0000) != (rop & 0x0f0000); +} + +/*********************************************************************** + * dibdrv_PutImage + */ +DWORD dibdrv_PutImage( PHYSDEV dev, HBITMAP hbitmap, HRGN clip, BITMAPINFO *info, + const struct gdi_image_bits *bits, struct bitblt_coords *src, + struct bitblt_coords *dst, DWORD rop ) +{ + dib_info *dib, stand_alone; + DWORD ret; + POINT origin; + dib_info src_dib; + HRGN saved_clip = NULL; + dibdrv_physdev *pdev = NULL; + const WINEREGION *clip_data; + int i, rop2; + + TRACE( "%p %p %p\n", dev, hbitmap, info ); + + if (!hbitmap && rop_uses_pat( rop )) + { + PHYSDEV next = GET_NEXT_PHYSDEV( dev, pPutImage ); + FIXME( "rop %08x unsupported, forwarding to graphics driver\n", rop ); + return next->funcs->pPutImage( next, 0, clip, info, bits, src, dst, rop ); + } + + if (hbitmap) + { + BITMAPOBJ *bmp = GDI_GetObjPtr( hbitmap, OBJ_BITMAP ); + + if (!bmp) return ERROR_INVALID_HANDLE; + assert(bmp->dib); + + if (!init_dib_info( &stand_alone, &bmp->dib->dsBmih, bmp->dib->dsBitfields, + bmp->color_table, bmp->nb_colors, bmp->dib->dsBm.bmBits, 0 )) + { + ret = ERROR_BAD_FORMAT; + goto done; + } + dib = &stand_alone; + rop = SRCCOPY; + } + else + { + pdev = get_dibdrv_pdev( dev ); + dib = &pdev->dib; + } + + if (info->bmiHeader.biPlanes != 1) goto update_format; + if (info->bmiHeader.biBitCount != dib->bit_count) goto update_format; + if (!matching_color_info( dib, info )) goto update_format; + if (!bits) + { + ret = ERROR_SUCCESS; + goto done; + } + if ((src->width != dst->width) || (src->height != dst->height)) + { + ret = ERROR_TRANSFORM_NOT_SUPPORTED; + goto done; + } + + init_dib_info_from_bitmapinfo( &src_dib, info, bits->ptr, 0 ); + src_dib.bits.is_copy = bits->is_copy; + + origin.x = src->visrect.left; + origin.y = src->visrect.top; + + if (!hbitmap) + { + if (clip) saved_clip = add_extra_clipping_region( pdev, clip ); + clip = pdev->clip; + } + + rop2 = ((rop >> 16) & 0xf) + 1; + + if (clip == NULL) dib->funcs->copy_rect( dib, &dst->visrect, &src_dib, &origin, rop2 ); + else + { + clip_data = get_wine_region( clip ); + for (i = 0; i < clip_data->numRects; i++) + { + RECT clipped_rect; + + if (intersect_rect( &clipped_rect, &dst->visrect, clip_data->rects + i )) + { + origin.x = src->visrect.left + clipped_rect.left - dst->visrect.left; + origin.y = src->visrect.top + clipped_rect.top - dst->visrect.top; + dib->funcs->copy_rect( dib, &clipped_rect, &src_dib, &origin, rop2 ); + } + } + release_wine_region( clip ); + } + ret = ERROR_SUCCESS; + + if (saved_clip) restore_clipping_region( pdev, saved_clip ); + + goto done; + +update_format: + info->bmiHeader.biPlanes = 1; + info->bmiHeader.biBitCount = dib->bit_count; + set_color_info( dib, info ); + ret = ERROR_BAD_FORMAT; + +done: + if (hbitmap) GDI_ReleaseObj( hbitmap ); + + return ret; +} diff --git a/dlls/gdi32/dibdrv/dc.c b/dlls/gdi32/dibdrv/dc.c index 03e3f65afeb..962c7da769f 100644 --- a/dlls/gdi32/dibdrv/dc.c +++ b/dlls/gdi32/dibdrv/dc.c @@ -66,8 +66,8 @@ static void init_bit_fields(dib_info *dib, const DWORD *bit_fields) calc_shift_and_len(dib->blue_mask, &dib->blue_shift, &dib->blue_len); } -static BOOL init_dib_info(dib_info *dib, const BITMAPINFOHEADER *bi, const DWORD *bit_fields, - RGBQUAD *color_table, int color_table_size, void *bits, enum dib_info_flags flags) +BOOL init_dib_info(dib_info *dib, const BITMAPINFOHEADER *bi, const DWORD *bit_fields, + RGBQUAD *color_table, int color_table_size, void *bits, enum dib_info_flags flags) { dib->bit_count = bi->biBitCount; dib->width = bi->biWidth; @@ -304,7 +304,7 @@ static void update_masks( dibdrv_physdev *pdev, INT rop ) * Temporarily add a region to the current clipping region. * The returned region must be restored with restore_clipping_region. */ -static HRGN add_extra_clipping_region( dibdrv_physdev *pdev, HRGN rgn ) +HRGN add_extra_clipping_region( dibdrv_physdev *pdev, HRGN rgn ) { HRGN ret, clip; @@ -318,7 +318,7 @@ static HRGN add_extra_clipping_region( dibdrv_physdev *pdev, HRGN rgn ) /*********************************************************************** * restore_clipping_region */ -static void restore_clipping_region( dibdrv_physdev *pdev, HRGN rgn ) +void restore_clipping_region( dibdrv_physdev *pdev, HRGN rgn ) { if (!rgn) return; DeleteObject( pdev->clip ); @@ -338,259 +338,6 @@ static BOOL dibdrv_DeleteDC( PHYSDEV dev ) return 0; } -static void set_color_info( const dib_info *dib, BITMAPINFO *info ) -{ - DWORD *masks = (DWORD *)info->bmiColors; - - info->bmiHeader.biCompression = BI_RGB; - info->bmiHeader.biClrUsed = 0; - - switch (info->bmiHeader.biBitCount) - { - case 1: - case 4: - case 8: - if (dib->color_table) - { - info->bmiHeader.biClrUsed = min( dib->color_table_size, 1 << dib->bit_count ); - memcpy( info->bmiColors, dib->color_table, - info->bmiHeader.biClrUsed * sizeof(RGBQUAD) ); - } - break; - case 16: - masks[0] = dib->red_mask; - masks[1] = dib->green_mask; - masks[2] = dib->blue_mask; - info->bmiHeader.biCompression = BI_BITFIELDS; - break; - case 32: - if (dib->funcs != &funcs_8888) - { - masks[0] = dib->red_mask; - masks[1] = dib->green_mask; - masks[2] = dib->blue_mask; - info->bmiHeader.biCompression = BI_BITFIELDS; - } - break; - } -} - -/*********************************************************************** - * dibdrv_GetImage - */ -static DWORD dibdrv_GetImage( PHYSDEV dev, HBITMAP hbitmap, BITMAPINFO *info, - struct gdi_image_bits *bits, struct bitblt_coords *src ) -{ - DWORD ret = ERROR_SUCCESS; - dib_info *dib, stand_alone; - - TRACE( "%p %p %p\n", dev, hbitmap, info ); - - info->bmiHeader.biSize = sizeof(info->bmiHeader); - info->bmiHeader.biPlanes = 1; - info->bmiHeader.biCompression = BI_RGB; - info->bmiHeader.biXPelsPerMeter = 0; - info->bmiHeader.biYPelsPerMeter = 0; - info->bmiHeader.biClrUsed = 0; - info->bmiHeader.biClrImportant = 0; - - if (hbitmap) - { - BITMAPOBJ *bmp = GDI_GetObjPtr( hbitmap, OBJ_BITMAP ); - - if (!bmp) return ERROR_INVALID_HANDLE; - assert(bmp->dib); - - if (!init_dib_info( &stand_alone, &bmp->dib->dsBmih, bmp->dib->dsBitfields, - bmp->color_table, bmp->nb_colors, bmp->dib->dsBm.bmBits, 0 )) - { - ret = ERROR_BAD_FORMAT; - goto done; - } - dib = &stand_alone; - } - else - { - dibdrv_physdev *pdev = get_dibdrv_pdev(dev); - dib = &pdev->dib; - } - - info->bmiHeader.biWidth = dib->width; - info->bmiHeader.biHeight = dib->stride > 0 ? -dib->height : dib->height; - info->bmiHeader.biBitCount = dib->bit_count; - info->bmiHeader.biSizeImage = dib->height * abs( dib->stride ); - - set_color_info( dib, info ); - - if (bits) - { - bits->ptr = dib->bits.ptr; - if (dib->stride < 0) - bits->ptr = (char *)bits->ptr + (dib->height - 1) * dib->stride; - bits->is_copy = FALSE; - bits->free = NULL; - } - -done: - if (hbitmap) GDI_ReleaseObj( hbitmap ); - return ret; -} - -static BOOL matching_color_info( const dib_info *dib, const BITMAPINFO *info ) -{ - switch (info->bmiHeader.biBitCount) - { - case 1: - case 4: - case 8: - { - RGBQUAD *color_table = (RGBQUAD *)((char *)info + info->bmiHeader.biSize); - if (dib->color_table_size != get_dib_num_of_colors( info )) return FALSE; - return !memcmp( color_table, dib->color_table, dib->color_table_size * sizeof(RGBQUAD) ); - } - - case 16: - { - DWORD *masks = (DWORD *)info->bmiColors; - if (info->bmiHeader.biCompression == BI_RGB) return dib->funcs == &funcs_555; - if (info->bmiHeader.biCompression == BI_BITFIELDS) - return masks[0] == dib->red_mask && masks[1] == dib->green_mask && masks[2] == dib->blue_mask; - break; - } - - case 24: - return TRUE; - - case 32: - { - DWORD *masks = (DWORD *)info->bmiColors; - if (info->bmiHeader.biCompression == BI_RGB) return dib->funcs == &funcs_8888; - if (info->bmiHeader.biCompression == BI_BITFIELDS) - return masks[0] == dib->red_mask && masks[1] == dib->green_mask && masks[2] == dib->blue_mask; - break; - } - - } - - return FALSE; -} - -static inline BOOL rop_uses_pat(DWORD rop) -{ - return ((rop >> 4) & 0x0f0000) != (rop & 0x0f0000); -} - - -/*********************************************************************** - * dibdrv_PutImage - */ -static DWORD dibdrv_PutImage( PHYSDEV dev, HBITMAP hbitmap, HRGN clip, BITMAPINFO *info, - const struct gdi_image_bits *bits, struct bitblt_coords *src, - struct bitblt_coords *dst, DWORD rop ) -{ - dib_info *dib, stand_alone; - DWORD ret; - POINT origin; - dib_info src_dib; - HRGN saved_clip = NULL; - dibdrv_physdev *pdev = NULL; - const WINEREGION *clip_data; - int i, rop2; - - TRACE( "%p %p %p\n", dev, hbitmap, info ); - - if (!hbitmap && rop_uses_pat( rop )) - { - PHYSDEV next = GET_NEXT_PHYSDEV( dev, pPutImage ); - FIXME( "rop %08x unsupported, forwarding to graphics driver\n", rop ); - return next->funcs->pPutImage( next, 0, clip, info, bits, src, dst, rop ); - } - - if (hbitmap) - { - BITMAPOBJ *bmp = GDI_GetObjPtr( hbitmap, OBJ_BITMAP ); - - if (!bmp) return ERROR_INVALID_HANDLE; - assert(bmp->dib); - - if (!init_dib_info( &stand_alone, &bmp->dib->dsBmih, bmp->dib->dsBitfields, - bmp->color_table, bmp->nb_colors, bmp->dib->dsBm.bmBits, 0 )) - { - ret = ERROR_BAD_FORMAT; - goto done; - } - dib = &stand_alone; - rop = SRCCOPY; - } - else - { - pdev = get_dibdrv_pdev( dev ); - dib = &pdev->dib; - } - - if (info->bmiHeader.biPlanes != 1) goto update_format; - if (info->bmiHeader.biBitCount != dib->bit_count) goto update_format; - if (!matching_color_info( dib, info )) goto update_format; - if (!bits) - { - ret = ERROR_SUCCESS; - goto done; - } - if ((src->width != dst->width) || (src->height != dst->height)) - { - ret = ERROR_TRANSFORM_NOT_SUPPORTED; - goto done; - } - - init_dib_info_from_bitmapinfo( &src_dib, info, bits->ptr, 0 ); - src_dib.bits.is_copy = bits->is_copy; - - origin.x = src->visrect.left; - origin.y = src->visrect.top; - - if (!hbitmap) - { - if (clip) saved_clip = add_extra_clipping_region( pdev, clip ); - clip = pdev->clip; - } - - rop2 = ((rop >> 16) & 0xf) + 1; - - if (clip == NULL) dib->funcs->copy_rect( dib, &dst->visrect, &src_dib, &origin, rop2 ); - else - { - clip_data = get_wine_region( clip ); - for (i = 0; i < clip_data->numRects; i++) - { - RECT clipped_rect; - - if (intersect_rect( &clipped_rect, &dst->visrect, clip_data->rects + i )) - { - origin.x = src->visrect.left + clipped_rect.left - dst->visrect.left; - origin.y = src->visrect.top + clipped_rect.top - dst->visrect.top; - dib->funcs->copy_rect( dib, &clipped_rect, &src_dib, &origin, rop2 ); - } - } - release_wine_region( clip ); - } - ret = ERROR_SUCCESS; - - if (saved_clip) restore_clipping_region( pdev, saved_clip ); - - goto done; - -update_format: - info->bmiHeader.biPlanes = 1; - info->bmiHeader.biBitCount = dib->bit_count; - set_color_info( dib, info ); - ret = ERROR_BAD_FORMAT; - -done: - if (hbitmap) GDI_ReleaseObj( hbitmap ); - - return ret; -} - /*********************************************************************** * dibdrv_SelectBitmap */ diff --git a/dlls/gdi32/dibdrv/dibdrv.h b/dlls/gdi32/dibdrv/dibdrv.h index 6727a6baf5e..2e555e30a74 100644 --- a/dlls/gdi32/dibdrv/dibdrv.h +++ b/dlls/gdi32/dibdrv/dibdrv.h @@ -18,12 +18,17 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +extern DWORD dibdrv_GetImage( PHYSDEV dev, HBITMAP hbitmap, BITMAPINFO *info, + struct gdi_image_bits *bits, struct bitblt_coords *src ) DECLSPEC_HIDDEN; extern BOOL dibdrv_LineTo( PHYSDEV dev, INT x, INT y ) DECLSPEC_HIDDEN; extern BOOL dibdrv_PatBlt( PHYSDEV dev, struct bitblt_coords *dst, DWORD rop ) DECLSPEC_HIDDEN; extern BOOL dibdrv_PaintRgn( PHYSDEV dev, HRGN hrgn ) DECLSPEC_HIDDEN; extern BOOL dibdrv_PolyPolyline( PHYSDEV dev, const POINT* pt, const DWORD* counts, DWORD polylines ) DECLSPEC_HIDDEN; extern BOOL dibdrv_Polyline( PHYSDEV dev, const POINT* pt, INT count ) DECLSPEC_HIDDEN; +extern DWORD dibdrv_PutImage( PHYSDEV dev, HBITMAP hbitmap, HRGN clip, BITMAPINFO *info, + const struct gdi_image_bits *bits, struct bitblt_coords *src, + struct bitblt_coords *dst, DWORD rop ) DECLSPEC_HIDDEN; extern BOOL dibdrv_Rectangle( PHYSDEV dev, INT left, INT top, INT right, INT bottom ) DECLSPEC_HIDDEN; extern HBRUSH dibdrv_SelectBrush( PHYSDEV dev, HBRUSH hbrush ) DECLSPEC_HIDDEN; extern HPEN dibdrv_SelectPen( PHYSDEV dev, HPEN hpen ) DECLSPEC_HIDDEN; @@ -69,13 +74,20 @@ extern void get_rop_codes(INT rop, struct rop_codes *codes); extern void calc_and_xor_masks(INT rop, DWORD color, DWORD *and, DWORD *xor) DECLSPEC_HIDDEN; extern void update_brush_rop( dibdrv_physdev *pdev, INT rop ) DECLSPEC_HIDDEN; extern void reset_dash_origin(dibdrv_physdev *pdev) DECLSPEC_HIDDEN; +extern BOOL init_dib_info(dib_info *dib, const BITMAPINFOHEADER *bi, const DWORD *bit_fields, + RGBQUAD *color_table, int color_table_size, void *bits, + enum dib_info_flags flags) DECLSPEC_HIDDEN; extern BOOL init_dib_info_from_packed(dib_info *dib, const BITMAPINFOHEADER *bi, WORD usage, HPALETTE pal) DECLSPEC_HIDDEN; +extern BOOL init_dib_info_from_bitmapinfo(dib_info *dib, const BITMAPINFO *info, void *bits, + enum dib_info_flags flags) DECLSPEC_HIDDEN; extern void free_dib_info(dib_info *dib) DECLSPEC_HIDDEN; extern void free_pattern_brush(dibdrv_physdev *pdev) DECLSPEC_HIDDEN; extern void copy_dib_color_info(dib_info *dst, const dib_info *src) DECLSPEC_HIDDEN; extern BOOL convert_dib(dib_info *dst, const dib_info *src) DECLSPEC_HIDDEN; extern DWORD get_fg_color(dibdrv_physdev *pdev, COLORREF color) DECLSPEC_HIDDEN; extern BOOL brush_rects( dibdrv_physdev *pdev, int num, const RECT *rects ) DECLSPEC_HIDDEN; +extern HRGN add_extra_clipping_region( dibdrv_physdev *pdev, HRGN rgn ) DECLSPEC_HIDDEN; +extern void restore_clipping_region( dibdrv_physdev *pdev, HRGN rgn ) DECLSPEC_HIDDEN; static inline BOOL defer_pen(dibdrv_physdev *pdev) {