From 8ae18d055a8af864087f08f127d7d93ad6eafbae Mon Sep 17 00:00:00 2001 From: Zhiyi Zhang Date: Tue, 20 Apr 2021 09:09:19 +0100 Subject: [PATCH] gdi32: Implement EMFDRV_AlphaBlend(). Fix a bug that Tally produces a blank print preview when images have to be scaled. Signed-off-by: Zhiyi Zhang Signed-off-by: Huw Davies Signed-off-by: Alexandre Julliard --- dlls/gdi32/enhmfdrv/bitblt.c | 88 ++++++++++++++++++++++++++++ dlls/gdi32/enhmfdrv/enhmetafiledrv.h | 2 + dlls/gdi32/enhmfdrv/init.c | 2 +- dlls/gdi32/tests/metafile.c | 4 +- 4 files changed, 92 insertions(+), 4 deletions(-) diff --git a/dlls/gdi32/enhmfdrv/bitblt.c b/dlls/gdi32/enhmfdrv/bitblt.c index 1fc5c0b1040..597a6110abd 100644 --- a/dlls/gdi32/enhmfdrv/bitblt.c +++ b/dlls/gdi32/enhmfdrv/bitblt.c @@ -27,6 +27,94 @@ #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 ) +{ + unsigned char src_buffer[FIELD_OFFSET(BITMAPINFO, bmiColors[256])]; + BITMAPINFO *src_info = (BITMAPINFO *)src_buffer; + UINT bits_size, bmi_size, emr_size, size, bpp; + struct gdi_image_bits bits; + EMRALPHABLEND *emr; + BITMAPINFO *bmi; + DC *dc_src; + DWORD err; + BOOL ret = FALSE; + + dc_src = get_physdev_dc(dev_src); + dev_src = GET_DC_PHYSDEV(dc_src, pGetImage); + err = dev_src->funcs->pGetImage(dev_src, src_info, &bits, src); + if (err) + { + SetLastError(err); + return FALSE; + } + + bpp = src_info->bmiHeader.biBitCount; + 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); + bits_size = src_info->bmiHeader.biSizeImage; + size = emr_size + bmi_size + bits_size; + + emr = HeapAlloc(GetProcessHeap(), 0, size); + if (!emr) goto err; + + 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; + + bmi = (BITMAPINFO *)((BYTE *)emr + emr->offBmiSrc); + memcpy(bmi, src_info, bmi_size); + memcpy((BYTE *)emr + emr->offBitsSrc, bits.ptr, bits_size); + + bmi->bmiHeader.biClrUsed = 0; + if (bmi->bmiHeader.biCompression == BI_RGB && bmi->bmiHeader.biBitCount == 16) + { + bmi->bmiHeader.biCompression = BI_BITFIELDS; + ((DWORD *)bmi->bmiColors)[0] = 0xf800; + ((DWORD *)bmi->bmiColors)[1] = 0x07e0; + ((DWORD *)bmi->bmiColors)[2] = 0x001f; + } + else if (bmi->bmiHeader.biCompression == BI_RGB && bmi->bmiHeader.biBitCount == 32) + { + bmi->bmiHeader.biCompression = BI_BITFIELDS; + ((DWORD *)bmi->bmiColors)[0] = 0xff0000; + ((DWORD *)bmi->bmiColors)[1] = 0x00ff00; + ((DWORD *)bmi->bmiColors)[2] = 0x0000ff; + } + + ret = EMFDRV_WriteRecord(dev_dst, (EMR *)emr); + if (ret) EMFDRV_UpdateBBox(dev_dst, &emr->rclBounds); + +err: + HeapFree(GetProcessHeap(), 0, emr); + if (bits.free) bits.free(&bits); + 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);