diff --git a/dlls/gdi32/dibdrv/bitblt.c b/dlls/gdi32/dibdrv/bitblt.c index 6b8a8b5507f..71ef2723f23 100644 --- a/dlls/gdi32/dibdrv/bitblt.c +++ b/dlls/gdi32/dibdrv/bitblt.c @@ -552,6 +552,35 @@ static void copy_rect( dib_info *dst, const RECT *dst_rect, const dib_info *src, } } +static void mask_rect( dib_info *dst, const RECT *dst_rect, const dib_info *src, const RECT *src_rect, + const struct clipped_rects *clipped_rects, INT rop2 ) +{ + POINT origin; + const RECT *rects; + int i, count; + + if (rop2 == R2_BLACK || rop2 == R2_NOT || rop2 == R2_NOP || rop2 == R2_WHITE) + return copy_rect( dst, dst_rect, src, src_rect, clipped_rects, rop2 ); + + if (clipped_rects) + { + rects = clipped_rects->rects; + count = clipped_rects->count; + } + else + { + rects = dst_rect; + count = 1; + } + + for (i = 0; i < count; i++) + { + origin.x = src_rect->left + rects[i].left - dst_rect->left; + origin.y = src_rect->top + rects[i].top - dst_rect->top; + dst->funcs->mask_rect( dst, &rects[i], src, &origin, rop2 ); + } +} + static DWORD blend_rect( dib_info *dst, const RECT *dst_rect, const dib_info *src, const RECT *src_rect, HRGN clip, BLENDFUNCTION blend ) { @@ -859,11 +888,15 @@ DWORD dibdrv_GetImage( PHYSDEV dev, BITMAPINFO *info, struct gdi_image_bits *bit return get_image_dib_info( &pdev->dib, info, bits, src ); } -static BOOL matching_color_info( const dib_info *dib, const BITMAPINFO *info ) +static BOOL matching_color_info( const dib_info *dib, const BITMAPINFO *info, BOOL allow_mask_rect ) { const RGBQUAD *color_table = info->bmiColors; if (info->bmiHeader.biPlanes != 1) return FALSE; + + if (allow_mask_rect && info->bmiHeader.biBitCount == 1 && dib->bit_count != 1) + return TRUE; + if (info->bmiHeader.biBitCount != dib->bit_count) return FALSE; switch (info->bmiHeader.biBitCount) @@ -918,7 +951,7 @@ DWORD put_image_into_bitmap( BITMAPOBJ *bmp, HRGN clip, BITMAPINFO *info, dib_info dib, src_dib; if (!init_dib_info_from_bitmapobj( &dib, bmp )) return ERROR_OUTOFMEMORY; - if (!matching_color_info( &dib, info )) goto update_format; + if (!matching_color_info( &dib, info, FALSE )) goto update_format; if (!bits) return ERROR_SUCCESS; if ((src->width != dst->width) || (src->height != dst->height)) return ERROR_TRANSFORM_NOT_SUPPORTED; @@ -957,12 +990,17 @@ DWORD dibdrv_PutImage( PHYSDEV dev, HRGN clip, BITMAPINFO *info, dib_info src_dib; HRGN tmp_rgn = 0; dibdrv_physdev *pdev = get_dibdrv_pdev( dev ); + BOOL stretch = (src->width != dst->width) || (src->height != dst->height); TRACE( "%p %p\n", dev, info ); - if (!matching_color_info( &pdev->dib, info )) goto update_format; + if (!matching_color_info( &pdev->dib, info, !stretch && !rop_uses_pat( rop ) )) goto update_format; if (!bits) return ERROR_SUCCESS; - if ((src->width != dst->width) || (src->height != dst->height)) return ERROR_TRANSFORM_NOT_SUPPORTED; + if (stretch) return ERROR_TRANSFORM_NOT_SUPPORTED; + + /* For mask_rect, 1-bpp source without a color table uses the destination DC colors */ + if (info->bmiHeader.biBitCount == 1 && pdev->dib.bit_count != 1 && !info->bmiHeader.biClrUsed) + get_mono_dc_colors( dev->hdc, info, 2 ); init_dib_info_from_bitmapinfo( &src_dib, info, bits->ptr ); src_dib.bits.is_copy = bits->is_copy; @@ -981,7 +1019,10 @@ DWORD dibdrv_PutImage( PHYSDEV dev, HRGN clip, BITMAPINFO *info, if (!rop_uses_pat( rop )) { int rop2 = ((rop >> 16) & 0xf) + 1; - copy_rect( &pdev->dib, &dst->visrect, &src_dib, &src->visrect, &clipped_rects, rop2 ); + if (pdev->dib.bit_count == info->bmiHeader.biBitCount) + copy_rect( &pdev->dib, &dst->visrect, &src_dib, &src->visrect, &clipped_rects, rop2 ); + else + mask_rect( &pdev->dib, &dst->visrect, &src_dib, &src->visrect, &clipped_rects, rop2 ); } else ret = execute_rop( pdev, &dst->visrect, &src_dib, &src->visrect, &clipped_rects, rop ); diff --git a/dlls/gdi32/dibdrv/dibdrv.h b/dlls/gdi32/dibdrv/dibdrv.h index fc28acc2b15..afd107d6132 100644 --- a/dlls/gdi32/dibdrv/dibdrv.h +++ b/dlls/gdi32/dibdrv/dibdrv.h @@ -187,6 +187,8 @@ typedef struct primitive_funcs void (* blend_rect)(const dib_info *dst, const RECT *rc, const dib_info *src, const POINT *origin, BLENDFUNCTION blend); BOOL (* gradient_rect)(const dib_info *dib, const RECT *rc, const TRIVERTEX *v, int mode); + void (* mask_rect)(const dib_info *dst, const RECT *rc, const dib_info *src, + const POINT *origin, int rop2); void (* draw_glyph)(const dib_info *dst, const RECT *rc, const dib_info *glyph, const POINT *origin, DWORD text_pixel, const struct intensity_range *ranges); void (* draw_subpixel_glyph)(const dib_info *dst, const RECT *rc, const dib_info *glyph, diff --git a/dlls/gdi32/dibdrv/primitives.c b/dlls/gdi32/dibdrv/primitives.c index dff940c544b..00b71f200a6 100644 --- a/dlls/gdi32/dibdrv/primitives.c +++ b/dlls/gdi32/dibdrv/primitives.c @@ -5019,6 +5019,345 @@ static BOOL gradient_rect_null( const dib_info *dib, const RECT *rc, const TRIVE return TRUE; } +static void mask_rect_32( const dib_info *dst, const RECT *rc, + const dib_info *src, const POINT *origin, int rop2 ) +{ + DWORD *dst_start = get_pixel_ptr_32(dst, rc->left, rc->top), dst_colors[2]; + DWORD src_val, bit_val, i, full, pos; + struct rop_codes codes; + int x, y; + const RGBQUAD *color_table = get_dib_color_table( src ); + BYTE *src_start = get_pixel_ptr_1(src, origin->x, origin->y); + + get_rop_codes( rop2, &codes ); + + if (dst->funcs == &funcs_8888) + for (i = 0; i < sizeof(dst_colors) / sizeof(dst_colors[0]); i++) + dst_colors[i] = color_table[i].rgbRed << 16 | color_table[i].rgbGreen << 8 | + color_table[i].rgbBlue; + else + for (i = 0; i < sizeof(dst_colors) / sizeof(dst_colors[0]); i++) + dst_colors[i] = put_field(color_table[i].rgbRed, dst->red_shift, dst->red_len) | + put_field(color_table[i].rgbGreen, dst->green_shift, dst->green_len) | + put_field(color_table[i].rgbBlue, dst->blue_shift, dst->blue_len); + + for (y = rc->top; y < rc->bottom; y++) + { + pos = origin->x & 7; + + for (x = 0; x < rc->right - rc->left && pos < 8; x++, pos++) + { + bit_val = (src_start[pos / 8] & pixel_masks_1[pos % 8]) ? 1 : 0; + do_rop_codes_32( dst_start + x, dst_colors[bit_val], &codes ); + } + + full = ((rc->right - rc->left) - x) / 8; + for (i = 0; i < full; i++, pos += 8) + { + src_val = src_start[pos / 8]; + + bit_val = (src_val >> 7) & 1; + do_rop_codes_32( dst_start + x++, dst_colors[bit_val], &codes ); + bit_val = (src_val >> 6) & 1; + do_rop_codes_32( dst_start + x++, dst_colors[bit_val], &codes ); + bit_val = (src_val >> 5) & 1; + do_rop_codes_32( dst_start + x++, dst_colors[bit_val], &codes ); + bit_val = (src_val >> 4) & 1; + do_rop_codes_32( dst_start + x++, dst_colors[bit_val], &codes ); + bit_val = (src_val >> 3) & 1; + do_rop_codes_32( dst_start + x++, dst_colors[bit_val], &codes ); + bit_val = (src_val >> 2) & 1; + do_rop_codes_32( dst_start + x++, dst_colors[bit_val], &codes ); + bit_val = (src_val >> 1) & 1; + do_rop_codes_32( dst_start + x++, dst_colors[bit_val], &codes ); + bit_val = src_val & 1; + do_rop_codes_32( dst_start + x++, dst_colors[bit_val], &codes ); + } + + for ( ; x < rc->right - rc->left; x++, pos++) + { + bit_val = (src_start[pos / 8] & pixel_masks_1[pos % 8]) ? 1 : 0; + do_rop_codes_32( dst_start + x, dst_colors[bit_val], &codes ); + } + + dst_start += dst->stride / 4; + src_start += src->stride; + } +} + +static void mask_rect_24( const dib_info *dst, const RECT *rc, + const dib_info *src, const POINT *origin, int rop2 ) +{ + BYTE *dst_start = get_pixel_ptr_24(dst, rc->left, rc->top); + DWORD src_val, bit_val, i, full, pos; + struct rop_codes codes; + int x, y; + const RGBQUAD *color_table = get_dib_color_table( src ); + BYTE *src_start = get_pixel_ptr_1(src, origin->x, origin->y); + RGBQUAD rgb; + + get_rop_codes( rop2, &codes ); + + for (y = rc->top; y < rc->bottom; y++) + { + pos = origin->x & 7; + + for (x = 0; x < rc->right - rc->left && pos < 8; x++, pos++) + { + bit_val = (src_start[pos / 8] & pixel_masks_1[pos % 8]) ? 1 : 0; + rgb = color_table[bit_val]; + do_rop_codes_8( dst_start + x * 3, rgb.rgbBlue, &codes ); + do_rop_codes_8( dst_start + x * 3 + 1, rgb.rgbGreen, &codes ); + do_rop_codes_8( dst_start + x * 3 + 2, rgb.rgbRed, &codes ); + } + + full = ((rc->right - rc->left) - x) / 8; + for (i = 0; i < full; i++, pos += 8) + { + src_val = src_start[pos / 8]; + + bit_val = (src_val >> 7) & 1; + rgb = color_table[bit_val]; + do_rop_codes_8( dst_start + x * 3, rgb.rgbBlue, &codes ); + do_rop_codes_8( dst_start + x * 3 + 1, rgb.rgbGreen, &codes ); + do_rop_codes_8( dst_start + x * 3 + 2, rgb.rgbRed, &codes ); + x++; + + bit_val = (src_val >> 6) & 1; + rgb = color_table[bit_val]; + do_rop_codes_8( dst_start + x * 3, rgb.rgbBlue, &codes ); + do_rop_codes_8( dst_start + x * 3 + 1, rgb.rgbGreen, &codes ); + do_rop_codes_8( dst_start + x * 3 + 2, rgb.rgbRed, &codes ); + x++; + + bit_val = (src_val >> 5) & 1; + rgb = color_table[bit_val]; + do_rop_codes_8( dst_start + x * 3, rgb.rgbBlue, &codes ); + do_rop_codes_8( dst_start + x * 3 + 1, rgb.rgbGreen, &codes ); + do_rop_codes_8( dst_start + x * 3 + 2, rgb.rgbRed, &codes ); + x++; + + bit_val = (src_val >> 4) & 1; + rgb = color_table[bit_val]; + do_rop_codes_8( dst_start + x * 3, rgb.rgbBlue, &codes ); + do_rop_codes_8( dst_start + x * 3 + 1, rgb.rgbGreen, &codes ); + do_rop_codes_8( dst_start + x * 3 + 2, rgb.rgbRed, &codes ); + x++; + + bit_val = (src_val >> 3) & 1; + rgb = color_table[bit_val]; + do_rop_codes_8( dst_start + x * 3, rgb.rgbBlue, &codes ); + do_rop_codes_8( dst_start + x * 3 + 1, rgb.rgbGreen, &codes ); + do_rop_codes_8( dst_start + x * 3 + 2, rgb.rgbRed, &codes ); + x++; + + bit_val = (src_val >> 2) & 1; + rgb = color_table[bit_val]; + do_rop_codes_8( dst_start + x * 3, rgb.rgbBlue, &codes ); + do_rop_codes_8( dst_start + x * 3 + 1, rgb.rgbGreen, &codes ); + do_rop_codes_8( dst_start + x * 3 + 2, rgb.rgbRed, &codes ); + x++; + + bit_val = (src_val >> 1) & 1; + rgb = color_table[bit_val]; + do_rop_codes_8( dst_start + x * 3, rgb.rgbBlue, &codes ); + do_rop_codes_8( dst_start + x * 3 + 1, rgb.rgbGreen, &codes ); + do_rop_codes_8( dst_start + x * 3 + 2, rgb.rgbRed, &codes ); + x++; + + bit_val = src_val & 1; + rgb = color_table[bit_val]; + do_rop_codes_8( dst_start + x * 3, rgb.rgbBlue, &codes ); + do_rop_codes_8( dst_start + x * 3 + 1, rgb.rgbGreen, &codes ); + do_rop_codes_8( dst_start + x * 3 + 2, rgb.rgbRed, &codes ); + x++; + } + + for ( ; x < rc->right - rc->left; x++, pos++) + { + bit_val = (src_start[pos / 8] & pixel_masks_1[pos % 8]) ? 1 : 0; + rgb = color_table[bit_val]; + do_rop_codes_8( dst_start + x * 3, rgb.rgbBlue, &codes ); + do_rop_codes_8( dst_start + x * 3 + 1, rgb.rgbGreen, &codes ); + do_rop_codes_8( dst_start + x * 3 + 2, rgb.rgbRed, &codes ); + } + + dst_start += dst->stride; + src_start += src->stride; + } +} + +static void mask_rect_16( const dib_info *dst, const RECT *rc, + const dib_info *src, const POINT *origin, int rop2 ) +{ + WORD *dst_start = get_pixel_ptr_16(dst, rc->left, rc->top), dst_colors[2]; + DWORD src_val, bit_val, i, full, pos; + struct rop_codes codes; + int x, y; + const RGBQUAD *color_table = get_dib_color_table( src ); + BYTE *src_start = get_pixel_ptr_1(src, origin->x, origin->y); + + get_rop_codes( rop2, &codes ); + + if (dst->funcs == &funcs_555) + for (i = 0; i < sizeof(dst_colors) / sizeof(dst_colors[0]); i++) + dst_colors[i] = ((color_table[i].rgbRed << 7) & 0x7c00) | + ((color_table[i].rgbGreen << 2) & 0x03e0) | + ((color_table[i].rgbBlue >> 3) & 0x001f); + else + for (i = 0; i < sizeof(dst_colors) / sizeof(dst_colors[0]); i++) + dst_colors[i] = put_field(color_table[i].rgbRed, dst->red_shift, dst->red_len) | + put_field(color_table[i].rgbGreen, dst->green_shift, dst->green_len) | + put_field(color_table[i].rgbBlue, dst->blue_shift, dst->blue_len); + + for (y = rc->top; y < rc->bottom; y++) + { + pos = origin->x & 7; + + for (x = 0; x < rc->right - rc->left && pos < 8; x++, pos++) + { + bit_val = (src_start[pos / 8] & pixel_masks_1[pos % 8]) ? 1 : 0; + do_rop_codes_16( dst_start + x, dst_colors[bit_val], &codes ); + } + + full = ((rc->right - rc->left) - x) / 8; + for (i = 0; i < full; i++, pos += 8) + { + src_val = src_start[pos / 8]; + + bit_val = (src_val >> 7) & 1; + do_rop_codes_16( dst_start + x++, dst_colors[bit_val], &codes ); + bit_val = (src_val >> 6) & 1; + do_rop_codes_16( dst_start + x++, dst_colors[bit_val], &codes ); + bit_val = (src_val >> 5) & 1; + do_rop_codes_16( dst_start + x++, dst_colors[bit_val], &codes ); + bit_val = (src_val >> 4) & 1; + do_rop_codes_16( dst_start + x++, dst_colors[bit_val], &codes ); + bit_val = (src_val >> 3) & 1; + do_rop_codes_16( dst_start + x++, dst_colors[bit_val], &codes ); + bit_val = (src_val >> 2) & 1; + do_rop_codes_16( dst_start + x++, dst_colors[bit_val], &codes ); + bit_val = (src_val >> 1) & 1; + do_rop_codes_16( dst_start + x++, dst_colors[bit_val], &codes ); + bit_val = src_val & 1; + do_rop_codes_16( dst_start + x++, dst_colors[bit_val], &codes ); + } + + for ( ; x < rc->right - rc->left; x++, pos++) + { + bit_val = (src_start[pos / 8] & pixel_masks_1[pos % 8]) ? 1 : 0; + do_rop_codes_16( dst_start + x, dst_colors[bit_val], &codes ); + } + + dst_start += dst->stride / 2; + src_start += src->stride; + } +} + +static void mask_rect_8( const dib_info *dst, const RECT *rc, + const dib_info *src, const POINT *origin, int rop2 ) +{ + BYTE *dst_start = get_pixel_ptr_8(dst, rc->left, rc->top), dst_colors[2]; + DWORD src_val, bit_val, i, full, pos; + struct rop_codes codes; + int x, y; + const RGBQUAD *color_table = get_dib_color_table( src ); + BYTE *src_start = get_pixel_ptr_1(src, origin->x, origin->y); + + get_rop_codes( rop2, &codes ); + + for (i = 0; i < sizeof(dst_colors) / sizeof(dst_colors[0]); i++) + dst_colors[i] = rgb_to_pixel_colortable( dst, color_table[i].rgbRed, color_table[i].rgbGreen, + color_table[i].rgbBlue ); + + for (y = rc->top; y < rc->bottom; y++) + { + pos = origin->x & 7; + + for (x = 0; x < rc->right - rc->left && pos < 8; x++, pos++) + { + bit_val = (src_start[pos / 8] & pixel_masks_1[pos % 8]) ? 1 : 0; + do_rop_codes_8( dst_start + x, dst_colors[bit_val], &codes ); + } + + full = ((rc->right - rc->left) - x) / 8; + for (i = 0; i < full; i++, pos += 8) + { + src_val = src_start[pos / 8]; + + bit_val = (src_val >> 7) & 1; + do_rop_codes_8( dst_start + x++, dst_colors[bit_val], &codes ); + bit_val = (src_val >> 6) & 1; + do_rop_codes_8( dst_start + x++, dst_colors[bit_val], &codes ); + bit_val = (src_val >> 5) & 1; + do_rop_codes_8( dst_start + x++, dst_colors[bit_val], &codes ); + bit_val = (src_val >> 4) & 1; + do_rop_codes_8( dst_start + x++, dst_colors[bit_val], &codes ); + bit_val = (src_val >> 3) & 1; + do_rop_codes_8( dst_start + x++, dst_colors[bit_val], &codes ); + bit_val = (src_val >> 2) & 1; + do_rop_codes_8( dst_start + x++, dst_colors[bit_val], &codes ); + bit_val = (src_val >> 1) & 1; + do_rop_codes_8( dst_start + x++, dst_colors[bit_val], &codes ); + bit_val = src_val & 1; + do_rop_codes_8( dst_start + x++, dst_colors[bit_val], &codes ); + } + + for ( ; x < rc->right - rc->left; x++, pos++) + { + bit_val = (src_start[pos / 8] & pixel_masks_1[pos % 8]) ? 1 : 0; + do_rop_codes_8( dst_start + x, dst_colors[bit_val], &codes ); + } + + dst_start += dst->stride; + src_start += src->stride; + } +} + +static void mask_rect_4( const dib_info *dst, const RECT *rc, + const dib_info *src, const POINT *origin, int rop2 ) +{ + BYTE *dst_start = get_pixel_ptr_4(dst, rc->left, rc->top), dst_colors[2], *dst_ptr; + DWORD bit_val, i, pos; + struct rop_codes codes; + int x, y; + int left = dst->rect.left + rc->left; + int right = dst->rect.left + rc->right; + const RGBQUAD *color_table = get_dib_color_table( src ); + BYTE *src_start = get_pixel_ptr_1(src, origin->x, origin->y); + + get_rop_codes( rop2, &codes ); + + for (i = 0; i < sizeof(dst_colors) / sizeof(dst_colors[0]); i++) + { + dst_colors[i] = rgb_to_pixel_colortable( dst, color_table[i].rgbRed, color_table[i].rgbGreen, + color_table[i].rgbBlue ); + /* Set high nibble to match so we don't need to shift it later. */ + dst_colors[i] |= dst_colors[i] << 4; + } + + for (y = rc->top; y < rc->bottom; y++) + { + pos = origin->x & 7; + + for (x = left, dst_ptr = dst_start; x < right; x++, pos++) + { + bit_val = (src_start[pos / 8] & pixel_masks_1[pos % 8]) ? 1 : 0; + if (x & 1) + do_rop_codes_mask_8( dst_ptr++, dst_colors[bit_val], &codes, 0x0f ); + else + do_rop_codes_mask_8( dst_ptr, dst_colors[bit_val], &codes, 0xf0 ); + } + dst_start += dst->stride; + src_start += src->stride; + } +} + +static void mask_rect_null( const dib_info *dst, const RECT *rc, + const dib_info *src, const POINT *origin, int rop2 ) +{ +} + static inline BYTE aa_color( BYTE dst, BYTE text, BYTE min_comp, BYTE max_comp ) { if (dst == text) return dst; @@ -6338,6 +6677,7 @@ const primitive_funcs funcs_8888 = copy_rect_32, blend_rect_8888, gradient_rect_8888, + mask_rect_32, draw_glyph_8888, draw_subpixel_glyph_8888, get_pixel_32, @@ -6358,6 +6698,7 @@ const primitive_funcs funcs_32 = copy_rect_32, blend_rect_32, gradient_rect_32, + mask_rect_32, draw_glyph_32, draw_subpixel_glyph_32, get_pixel_32, @@ -6378,6 +6719,7 @@ const primitive_funcs funcs_24 = copy_rect_24, blend_rect_24, gradient_rect_24, + mask_rect_24, draw_glyph_24, draw_subpixel_glyph_24, get_pixel_24, @@ -6398,6 +6740,7 @@ const primitive_funcs funcs_555 = copy_rect_16, blend_rect_555, gradient_rect_555, + mask_rect_16, draw_glyph_555, draw_subpixel_glyph_555, get_pixel_16, @@ -6418,6 +6761,7 @@ const primitive_funcs funcs_16 = copy_rect_16, blend_rect_16, gradient_rect_16, + mask_rect_16, draw_glyph_16, draw_subpixel_glyph_16, get_pixel_16, @@ -6438,6 +6782,7 @@ const primitive_funcs funcs_8 = copy_rect_8, blend_rect_8, gradient_rect_8, + mask_rect_8, draw_glyph_8, draw_subpixel_glyph_null, get_pixel_8, @@ -6458,6 +6803,7 @@ const primitive_funcs funcs_4 = copy_rect_4, blend_rect_4, gradient_rect_4, + mask_rect_4, draw_glyph_4, draw_subpixel_glyph_null, get_pixel_4, @@ -6478,6 +6824,7 @@ const primitive_funcs funcs_1 = copy_rect_1, blend_rect_1, gradient_rect_1, + mask_rect_null, draw_glyph_1, draw_subpixel_glyph_null, get_pixel_1, @@ -6498,6 +6845,7 @@ const primitive_funcs funcs_null = copy_rect_null, blend_rect_null, gradient_rect_null, + mask_rect_null, draw_glyph_null, draw_subpixel_glyph_null, get_pixel_null,