Fix a bug that Tally produces a blank print preview when images have to be scaled.
Signed-off-by: Zhiyi Zhang zzhang@codeweavers.com --- dlls/gdi32/enhmfdrv/bitblt.c | 85 ++++++++++++++++++++++++++++ dlls/gdi32/enhmfdrv/enhmetafiledrv.h | 2 + dlls/gdi32/enhmfdrv/init.c | 2 +- dlls/gdi32/tests/metafile.c | 4 +- 4 files changed, 89 insertions(+), 4 deletions(-)
diff --git a/dlls/gdi32/enhmfdrv/bitblt.c b/dlls/gdi32/enhmfdrv/bitblt.c index 1fc5c0b1040..f0be2b52fc0 100644 --- a/dlls/gdi32/enhmfdrv/bitblt.c +++ b/dlls/gdi32/enhmfdrv/bitblt.c @@ -27,6 +27,91 @@ #include "enhmetafiledrv.h" #include "wine/debug.h"
+BOOL CDECL EMFDRV_AlphaBlend( PHYSDEV dev_dst, struct bitblt_coords *dst, PHYSDEV dev_src, + struct bitblt_coords *src, BLENDFUNCTION func ) +{ + UINT bits_size, bmi_size, emr_size, size, bpp; + BITMAPINFOHEADER *bmih; + EMRALPHABLEND *emr; + HBITMAP hbitmap; + BITMAP bitmap; + BOOL ret; + + /* can't use a metafile DC as source */ + if (dev_src->funcs == dev_dst->funcs) + return FALSE; + + hbitmap = GetCurrentObject(dev_src->hdc, OBJ_BITMAP); + if (GetObjectW(hbitmap, sizeof(BITMAP), &bitmap) != sizeof(BITMAP)) + return FALSE; + + bpp = bitmap.bmPlanes * bitmap.bmBitsPixel; + bits_size = get_dib_stride(bitmap.bmWidth, bpp) * bitmap.bmHeight; + if (bpp <= 8) + bmi_size = sizeof(BITMAPINFOHEADER) + (1 << bpp) * sizeof(RGBQUAD); + else if (bpp == 16 || bpp == 32) + bmi_size = sizeof(BITMAPINFOHEADER) + 3 * sizeof(RGBQUAD); + else + bmi_size = sizeof(BITMAPINFOHEADER); + emr_size = sizeof(EMRALPHABLEND); + size = emr_size + bmi_size + bits_size; + + emr = HeapAlloc(GetProcessHeap(), 0, size); + if (!emr) + return FALSE; + + emr->emr.iType = EMR_ALPHABLEND; + emr->emr.nSize = size; + emr->rclBounds.left = dst->log_x; + emr->rclBounds.top = dst->log_y; + emr->rclBounds.right = dst->log_x + dst->log_width - 1; + emr->rclBounds.bottom = dst->log_y + dst->log_height - 1; + emr->xDest = dst->log_x; + emr->yDest = dst->log_y; + emr->cxDest = dst->log_width; + emr->cyDest = dst->log_height; + emr->xSrc = src->log_x; + emr->ySrc = src->log_y; + emr->cxSrc = src->log_width; + emr->cySrc = src->log_height; + emr->dwRop = *(DWORD *)&func; + GetTransform(dev_src->hdc, 0x204, &emr->xformSrc); + emr->crBkColorSrc = GetBkColor(dev_src->hdc); + emr->iUsageSrc = DIB_RGB_COLORS; + emr->offBmiSrc = emr_size; + emr->cbBmiSrc = bmi_size; + emr->offBitsSrc = emr_size + bmi_size; + emr->cbBitsSrc = bits_size; + + bmih = (BITMAPINFOHEADER *)((BYTE *)emr + emr->offBmiSrc); + bmih->biSize = sizeof(BITMAPINFOHEADER); + bmih->biWidth = bitmap.bmWidth; + bmih->biHeight = bitmap.bmHeight; + bmih->biPlanes = bitmap.bmPlanes; + bmih->biBitCount = bpp; + bmih->biCompression = (bpp == 16 || bpp == 32) ? BI_BITFIELDS : BI_RGB; + bmih->biSizeImage = bits_size; + bmih->biYPelsPerMeter = 0; + bmih->biXPelsPerMeter = 0; + bmih->biClrUsed = bpp <= 8 ? 1 << bpp : 0; + bmih->biClrImportant = 0; + + if (GetDIBits(dev_src->hdc, hbitmap, 0, (UINT)bmih->biHeight, (BYTE *)emr + emr->offBitsSrc, + (BITMAPINFO *)bmih, DIB_RGB_COLORS)) + { + ret = EMFDRV_WriteRecord(dev_dst, (EMR *)emr); + if (ret) + EMFDRV_UpdateBBox(dev_dst, &emr->rclBounds); + } + else + { + ret = FALSE; + } + + HeapFree(GetProcessHeap(), 0, emr); + return ret; +} + BOOL CDECL EMFDRV_PatBlt( PHYSDEV dev, struct bitblt_coords *dst, DWORD rop ) { EMRBITBLT emr; diff --git a/dlls/gdi32/enhmfdrv/enhmetafiledrv.h b/dlls/gdi32/enhmfdrv/enhmetafiledrv.h index ec83d29c735..253f96cd8ec 100644 --- a/dlls/gdi32/enhmfdrv/enhmetafiledrv.h +++ b/dlls/gdi32/enhmfdrv/enhmetafiledrv.h @@ -58,6 +58,8 @@ extern DWORD EMFDRV_CreateBrushIndirect( PHYSDEV dev, HBRUSH hBrush ) DECLSPEC_H
/* Metafile driver functions */ extern BOOL CDECL EMFDRV_AbortPath( PHYSDEV dev ) DECLSPEC_HIDDEN; +extern BOOL CDECL EMFDRV_AlphaBlend( PHYSDEV dev_dst, struct bitblt_coords *dst, + PHYSDEV dev_src, struct bitblt_coords *src, BLENDFUNCTION func ) DECLSPEC_HIDDEN; extern BOOL CDECL EMFDRV_AngleArc( PHYSDEV dev, INT x, INT y, DWORD radius, FLOAT start, FLOAT sweep ) DECLSPEC_HIDDEN; extern BOOL CDECL EMFDRV_Arc( PHYSDEV dev, INT left, INT top, INT right, INT bottom, INT xstart, INT ystart, INT xend, INT yend ) DECLSPEC_HIDDEN; diff --git a/dlls/gdi32/enhmfdrv/init.c b/dlls/gdi32/enhmfdrv/init.c index cf9fb923633..07416db265e 100644 --- a/dlls/gdi32/enhmfdrv/init.c +++ b/dlls/gdi32/enhmfdrv/init.c @@ -38,7 +38,7 @@ static const struct gdi_dc_funcs emfdrv_driver = { NULL, /* pAbortDoc */ EMFDRV_AbortPath, /* pAbortPath */ - NULL, /* pAlphaBlend */ + EMFDRV_AlphaBlend, /* pAlphaBlend */ EMFDRV_AngleArc, /* pAngleArc */ EMFDRV_Arc, /* pArc */ EMFDRV_ArcTo, /* pArcTo */ diff --git a/dlls/gdi32/tests/metafile.c b/dlls/gdi32/tests/metafile.c index ec9c7894574..9340e20444a 100644 --- a/dlls/gdi32/tests/metafile.c +++ b/dlls/gdi32/tests/metafile.c @@ -5001,15 +5001,13 @@ static void test_emf_AlphaBlend(void) ret = BitBlt(hdc_bitmap, 0, 0, bitmap_width, bitmap_height, 0, 0, 0, BLACKNESS); ok(ret, "Test %d: BitBlt failed, error %d\n", test_idx, GetLastError()); ret = GdiAlphaBlend(hdc_emf, 0, 0, bitmap_width, bitmap_height, hdc_bitmap, 0, 0, 400, 400, blend); - todo_wine ok(ret, "Test %d: GdiAlphaBlend failed, error %d\n", test_idx, GetLastError());
hemf = CloseEnhMetaFile(hdc_emf); ok(!!hemf, "Test %d: CloseEnhMetaFile failed, %d\n", test_idx, GetLastError());
sprintf(comment, "test_emf_AlphaBlend() test %d", test_idx); - if (ret) - ret = compare_emf_bits(hemf, tests[test_idx].bits, tests[test_idx].bits_count, comment, FALSE); + ret = compare_emf_bits(hemf, tests[test_idx].bits, tests[test_idx].bits_count, comment, FALSE); if (ret) { dump_emf_bits(hemf, comment);
On Wed, Apr 14, 2021 at 03:27:57PM +0800, Zhiyi Zhang wrote:
Fix a bug that Tally produces a blank print preview when images have to be scaled.
Signed-off-by: Zhiyi Zhang zzhang@codeweavers.com
dlls/gdi32/enhmfdrv/bitblt.c | 85 ++++++++++++++++++++++++++++ dlls/gdi32/enhmfdrv/enhmetafiledrv.h | 2 + dlls/gdi32/enhmfdrv/init.c | 2 +- dlls/gdi32/tests/metafile.c | 4 +- 4 files changed, 89 insertions(+), 4 deletions(-)
diff --git a/dlls/gdi32/enhmfdrv/bitblt.c b/dlls/gdi32/enhmfdrv/bitblt.c index 1fc5c0b1040..f0be2b52fc0 100644 --- a/dlls/gdi32/enhmfdrv/bitblt.c +++ b/dlls/gdi32/enhmfdrv/bitblt.c @@ -27,6 +27,91 @@ #include "enhmetafiledrv.h" #include "wine/debug.h"
+BOOL CDECL EMFDRV_AlphaBlend( PHYSDEV dev_dst, struct bitblt_coords *dst, PHYSDEV dev_src,
struct bitblt_coords *src, BLENDFUNCTION func )
+{
- UINT bits_size, bmi_size, emr_size, size, bpp;
- BITMAPINFOHEADER *bmih;
- EMRALPHABLEND *emr;
- HBITMAP hbitmap;
- BITMAP bitmap;
- BOOL ret;
- /* can't use a metafile DC as source */
- if (dev_src->funcs == dev_dst->funcs)
return FALSE;
- hbitmap = GetCurrentObject(dev_src->hdc, OBJ_BITMAP);
- if (GetObjectW(hbitmap, sizeof(BITMAP), &bitmap) != sizeof(BITMAP))
return FALSE;
This would likely be cleaner using the BlendImage entry point (likewise I suspect StretchBlt would benefit from using PutImage).
Huw.
On 4/15/21 3:31 PM, Huw Davies wrote:
On Wed, Apr 14, 2021 at 03:27:57PM +0800, Zhiyi Zhang wrote:
Fix a bug that Tally produces a blank print preview when images have to be scaled.
Signed-off-by: Zhiyi Zhang zzhang@codeweavers.com
dlls/gdi32/enhmfdrv/bitblt.c | 85 ++++++++++++++++++++++++++++ dlls/gdi32/enhmfdrv/enhmetafiledrv.h | 2 + dlls/gdi32/enhmfdrv/init.c | 2 +- dlls/gdi32/tests/metafile.c | 4 +- 4 files changed, 89 insertions(+), 4 deletions(-)
diff --git a/dlls/gdi32/enhmfdrv/bitblt.c b/dlls/gdi32/enhmfdrv/bitblt.c index 1fc5c0b1040..f0be2b52fc0 100644 --- a/dlls/gdi32/enhmfdrv/bitblt.c +++ b/dlls/gdi32/enhmfdrv/bitblt.c @@ -27,6 +27,91 @@ #include "enhmetafiledrv.h" #include "wine/debug.h"
+BOOL CDECL EMFDRV_AlphaBlend( PHYSDEV dev_dst, struct bitblt_coords *dst, PHYSDEV dev_src,
struct bitblt_coords *src, BLENDFUNCTION func )
+{
- UINT bits_size, bmi_size, emr_size, size, bpp;
- BITMAPINFOHEADER *bmih;
- EMRALPHABLEND *emr;
- HBITMAP hbitmap;
- BITMAP bitmap;
- BOOL ret;
- /* can't use a metafile DC as source */
- if (dev_src->funcs == dev_dst->funcs)
return FALSE;
- hbitmap = GetCurrentObject(dev_src->hdc, OBJ_BITMAP);
- if (GetObjectW(hbitmap, sizeof(BITMAP), &bitmap) != sizeof(BITMAP))
return FALSE;
This would likely be cleaner using the BlendImage entry point (likewise I suspect StretchBlt would benefit from using PutImage).
Huw.
Hi Huw,
I am afraid that it's not cleaner in practice. There are a few issues that make it less intuitive if I use the BlendImage entry point. 1. EMR_ALPHABLEND needs source DC to get world transform and background color, so we need to add a src_dev parameter to all BlendImage function calls. 2. EMR_ALPHABLEND records always use BI_BITFIELDS compression when the source image is 16 bit or 32 bit. Something like the following in gdi32/dib.c#line 1367 in GetDIBits() needs to be added to the EMR_BlendImage entry point. So we can't copy BITMAPINFOHEADER directly using memcpy().
/* if the src and dst are the same depth, copy the colour info across */ if (dst_info->bmiHeader.biBitCount == src_info->bmiHeader.biBitCount && coloruse == DIB_RGB_COLORS ) { switch (src_info->bmiHeader.biBitCount) { case 16: if (src_info->bmiHeader.biCompression == BI_RGB) { src_info->bmiHeader.biCompression = BI_BITFIELDS; memcpy( src_info->bmiColors, bit_fields_555, sizeof(bit_fields_555) ); } break; case 32: if (src_info->bmiHeader.biCompression == BI_RGB) { src_info->bmiHeader.biCompression = BI_BITFIELDS; memcpy( src_info->bmiColors, bit_fields_888, sizeof(bit_fields_888) ); } break; } copy_color_info( dst_info, src_info, coloruse ); }
Also need to reset biClrUsed to 0 as gdi32/dib.c#line 1462 in GetDIBits() to pass all the tests.
if (info->bmiHeader.biSize != sizeof(BITMAPCOREHEADER)) { info->bmiHeader.biClrUsed = 0; info->bmiHeader.biSizeImage = get_dib_image_size( info ); }
So it turns out messier than using EMFDRV_AlphaBlend() if we need to add these special handling for bitmaps in different format. I think it's better to stick with EMFDRV_AlphaBlend().
Thanks, Zhiyi
On Sun, Apr 18, 2021 at 09:00:44PM +0800, Zhiyi Zhang wrote:
On 4/15/21 3:31 PM, Huw Davies wrote:
On Wed, Apr 14, 2021 at 03:27:57PM +0800, Zhiyi Zhang wrote:
Fix a bug that Tally produces a blank print preview when images have to be scaled.
Signed-off-by: Zhiyi Zhang zzhang@codeweavers.com
dlls/gdi32/enhmfdrv/bitblt.c | 85 ++++++++++++++++++++++++++++ dlls/gdi32/enhmfdrv/enhmetafiledrv.h | 2 + dlls/gdi32/enhmfdrv/init.c | 2 +- dlls/gdi32/tests/metafile.c | 4 +- 4 files changed, 89 insertions(+), 4 deletions(-)
diff --git a/dlls/gdi32/enhmfdrv/bitblt.c b/dlls/gdi32/enhmfdrv/bitblt.c index 1fc5c0b1040..f0be2b52fc0 100644 --- a/dlls/gdi32/enhmfdrv/bitblt.c +++ b/dlls/gdi32/enhmfdrv/bitblt.c @@ -27,6 +27,91 @@ #include "enhmetafiledrv.h" #include "wine/debug.h"
+BOOL CDECL EMFDRV_AlphaBlend( PHYSDEV dev_dst, struct bitblt_coords *dst, PHYSDEV dev_src,
struct bitblt_coords *src, BLENDFUNCTION func )
+{
- UINT bits_size, bmi_size, emr_size, size, bpp;
- BITMAPINFOHEADER *bmih;
- EMRALPHABLEND *emr;
- HBITMAP hbitmap;
- BITMAP bitmap;
- BOOL ret;
- /* can't use a metafile DC as source */
- if (dev_src->funcs == dev_dst->funcs)
return FALSE;
- hbitmap = GetCurrentObject(dev_src->hdc, OBJ_BITMAP);
- if (GetObjectW(hbitmap, sizeof(BITMAP), &bitmap) != sizeof(BITMAP))
return FALSE;
This would likely be cleaner using the BlendImage entry point (likewise I suspect StretchBlt would benefit from using PutImage).
I am afraid that it's not cleaner in practice. There are a few issues that make it less intuitive if I use the BlendImage entry point.
- EMR_ALPHABLEND needs source DC to get world transform and background color, so we need to add a src_dev parameter to all BlendImage function calls.
Ah right. In which case, as you say, we will need to implement EMFDRV_AlphaBlend(). However to get the src bits call src's pGetImage(), something like this (see nulldrv_AlphaBlend()):
DC *dc_src = get_physdev_dc( src_dev ); ... src_dev = GET_DC_PHYSDEV( dc_src, pGetImage ); err = src_dev->funcs->pGetImage( src_dev, src_info, &bits, src );
The point is that this will work for src dcs that belong to the display drivers too.
- EMR_ALPHABLEND records always use BI_BITFIELDS compression when
the source image is 16 bit or 32 bit. Something like the following in gdi32/dib.c#line 1367 in GetDIBits()
...
Also need to reset biClrUsed to 0 as gdi32/dib.c#line 1462 in GetDIBits() to pass all the tests.
Fixing up these shouldn't be too horrible.
Huw.