Signed-off-by: Shawn M. Chapla schapla@codeweavers.com --- v2: - Use L"description" rather than explicitly spelling out a WCHAR string.
dlls/gdiplus/tests/metafile.c | 122 ++++++++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+)
diff --git a/dlls/gdiplus/tests/metafile.c b/dlls/gdiplus/tests/metafile.c index 3ffdb7b0e9..c8bb89a776 100644 --- a/dlls/gdiplus/tests/metafile.c +++ b/dlls/gdiplus/tests/metafile.c @@ -2832,6 +2832,127 @@ static void test_fillpath(void) expect(GenericError, stat); }
+static const emfplus_record restoredc_records[] = { + { EMR_HEADER }, + { EMR_CREATEBRUSHINDIRECT }, + { EMR_SELECTOBJECT }, + + { EMR_SAVEDC }, + { EMR_SETVIEWPORTORGEX }, + { EMR_SAVEDC }, + { EMR_SETVIEWPORTORGEX }, + { EMR_SAVEDC }, + { EMR_SETVIEWPORTORGEX }, + + { EMR_RECTANGLE }, + + { EMR_RESTOREDC }, + { EMR_RECTANGLE }, + + { EMR_RESTOREDC }, + { EMR_RECTANGLE }, + + { EMR_SELECTOBJECT }, + { EMR_DELETEOBJECT }, + { EMR_EOF }, + { 0 } +}; + +static void test_restoredc(void) +{ + static const GpPointF dst_points[3] = {{0.0,0.0},{100.0,0.0},{0.0,100.0}}; + static const GpRectF frame = {0.0, 0.0, 100.0, 100.0}; + + GpBitmap *bitmap; + GpGraphics *graphics; + GpMetafile *metafile; + GpStatus stat; + HDC hdc, metafile_dc; + HBRUSH hbrush, holdbrush; + ARGB color; + + hdc = CreateCompatibleDC(0); + + stat = GdipRecordMetafile(hdc, EmfTypeEmfOnly, &frame, MetafileFrameUnitPixel, + L"winetest", &metafile); + expect(Ok, stat); + + DeleteDC(hdc); + + stat = GdipGetImageGraphicsContext((GpImage*)metafile, &graphics); + expect(Ok, stat); + + stat = GdipGetDC(graphics, &metafile_dc); + expect(Ok, stat); + + hbrush = CreateSolidBrush(0xff0000); + holdbrush = SelectObject(metafile_dc, hbrush); + + SaveDC(metafile_dc); + SetViewportOrgEx(metafile_dc, 20, 20, NULL); + + SaveDC(metafile_dc); + SetViewportOrgEx(metafile_dc, 40, 40, NULL); + + SaveDC(metafile_dc); + SetViewportOrgEx(metafile_dc, 60, 60, NULL); + + Rectangle(metafile_dc, 0, 0, 3, 3); + RestoreDC(metafile_dc, -2); + + Rectangle(metafile_dc, 0, 0, 3, 3); + RestoreDC(metafile_dc, -1); + + Rectangle(metafile_dc, 0, 0, 3, 3); + + SelectObject(metafile_dc, holdbrush); + DeleteObject(hbrush); + + stat = GdipReleaseDC(graphics, metafile_dc); + expect(Ok, stat); + + stat = GdipDeleteGraphics(graphics); + expect(Ok, stat); + + check_metafile(metafile, restoredc_records, "restoredc metafile", dst_points, + &frame, UnitPixel); + sync_metafile(&metafile, "restoredc.emf"); + + stat = GdipCreateBitmapFromScan0(100, 100, 0, PixelFormat32bppARGB, NULL, &bitmap); + expect(Ok, stat); + + stat = GdipGetImageGraphicsContext((GpImage*)bitmap, &graphics); + expect(Ok, stat); + + play_metafile(metafile, graphics, restoredc_records, "restoredc playback", dst_points, + &frame, UnitPixel); + + stat = GdipBitmapGetPixel(bitmap, 1, 1, &color); + expect(Ok, stat); + expect(0xff0000ff, color); + + stat = GdipBitmapGetPixel(bitmap, 21, 21, &color); + expect(Ok, stat); + todo_wine expect(0xff0000ff, color); + + stat = GdipBitmapGetPixel(bitmap, 41, 41, &color); + expect(Ok, stat); + expect(0, color); + + stat = GdipBitmapGetPixel(bitmap, 61, 61, &color); + expect(Ok, stat); + todo_wine expect(0xff0000ff, color); + + stat = GdipDeleteGraphics(graphics); + expect(Ok, stat); + + stat = GdipDisposeImage((GpImage*)bitmap); + expect(Ok, stat); + + stat = GdipDisposeImage((GpImage*)metafile); + expect(Ok, stat); +} + START_TEST(metafile) { struct GdiplusStartupInput gdiplusStartupInput; @@ -2880,6 +3001,7 @@ START_TEST(metafile) test_properties(); test_drawpath(); test_fillpath(); + test_restoredc();
GdiplusShutdown(gdiplusToken); }
Signed-off-by: Shawn M. Chapla schapla@codeweavers.com --- dlls/gdiplus/gdiplus_private.h | 1 - dlls/gdiplus/metafile.c | 124 ++++++--------------------------- dlls/gdiplus/tests/metafile.c | 4 +- 3 files changed, 24 insertions(+), 105 deletions(-)
diff --git a/dlls/gdiplus/gdiplus_private.h b/dlls/gdiplus/gdiplus_private.h index d62860360a..2ceaeade01 100644 --- a/dlls/gdiplus/gdiplus_private.h +++ b/dlls/gdiplus/gdiplus_private.h @@ -416,7 +416,6 @@ struct GpMetafile{ GpRectF src_rect; HANDLETABLE *handle_table; int handle_count; - XFORM gdiworldtransform; GpMatrix *world_transform; GpUnit page_unit; REAL page_scale; diff --git a/dlls/gdiplus/metafile.c b/dlls/gdiplus/metafile.c index f0dacab498..9ab8b1325f 100644 --- a/dlls/gdiplus/metafile.c +++ b/dlls/gdiplus/metafile.c @@ -1644,50 +1644,12 @@ GpStatus WINGDIPAPI GdipGetHemfFromMetafile(GpMetafile *metafile, HENHMETAFILE * return Ok; }
-static void METAFILE_GetFinalGdiTransform(const GpMetafile *metafile, XFORM *result) -{ - const GpRectF *rect; - const GpPointF *pt; - - /* This transforms metafile device space to output points. */ - rect = &metafile->src_rect; - pt = metafile->playback_points; - result->eM11 = (pt[1].X - pt[0].X) / rect->Width; - result->eM21 = (pt[2].X - pt[0].X) / rect->Height; - result->eDx = pt[0].X - result->eM11 * rect->X - result->eM21 * rect->Y; - result->eM12 = (pt[1].Y - pt[0].Y) / rect->Width; - result->eM22 = (pt[2].Y - pt[0].Y) / rect->Height; - result->eDy = pt[0].Y - result->eM12 * rect->X - result->eM22 * rect->Y; -} - -static GpStatus METAFILE_PlaybackUpdateGdiTransform(GpMetafile *metafile) -{ - XFORM combined, final; - - METAFILE_GetFinalGdiTransform(metafile, &final); - - CombineTransform(&combined, &metafile->gdiworldtransform, &final); - - SetGraphicsMode(metafile->playback_dc, GM_ADVANCED); - SetWorldTransform(metafile->playback_dc, &combined); - - return Ok; -} - static GpStatus METAFILE_PlaybackGetDC(GpMetafile *metafile) { GpStatus stat = Ok;
stat = GdipGetDC(metafile->playback_graphics, &metafile->playback_dc);
- if (stat == Ok) - { - static const XFORM identity = {1, 0, 0, 1, 0, 0}; - - metafile->gdiworldtransform = identity; - METAFILE_PlaybackUpdateGdiTransform(metafile); - } - return stat; }
@@ -2528,71 +2490,22 @@ GpStatus WINGDIPAPI GdipPlayMetafileRecord(GDIPCONST GpMetafile *metafile, /* regular EMF record */ if (metafile->playback_dc) { - switch (recordType) - { - case EMR_SETMAPMODE: - case EMR_SAVEDC: - case EMR_RESTOREDC: - case EMR_SETWINDOWORGEX: - case EMR_SETWINDOWEXTEX: - case EMR_SETVIEWPORTORGEX: - case EMR_SETVIEWPORTEXTEX: - case EMR_SCALEVIEWPORTEXTEX: - case EMR_SCALEWINDOWEXTEX: - case EMR_MODIFYWORLDTRANSFORM: - FIXME("not implemented for record type %x\n", recordType); - break; - case EMR_SETWORLDTRANSFORM: - { - const XFORM* xform = (void*)data; - real_metafile->gdiworldtransform = *xform; - METAFILE_PlaybackUpdateGdiTransform(real_metafile); - break; - } - case EMR_EXTSELECTCLIPRGN: - { - DWORD rgndatasize = *(DWORD*)data; - DWORD mode = *(DWORD*)(data + 4); - const RGNDATA *rgndata = (const RGNDATA*)(data + 8); - HRGN hrgn = NULL; - - if (dataSize > 8) - { - XFORM final; - - METAFILE_GetFinalGdiTransform(metafile, &final); - - hrgn = ExtCreateRegion(&final, rgndatasize, rgndata); - } - - ExtSelectClipRgn(metafile->playback_dc, hrgn, mode); - - DeleteObject(hrgn); + ENHMETARECORD *record = heap_alloc_zero(dataSize + 8);
- return Ok; - } - default: + if (record) { - ENHMETARECORD *record = heap_alloc_zero(dataSize + 8); - - if (record) - { - record->iType = recordType; - record->nSize = dataSize + 8; - memcpy(record->dParm, data, dataSize); - - if(PlayEnhMetaFileRecord(metafile->playback_dc, metafile->handle_table, - record, metafile->handle_count) == 0) - ERR("PlayEnhMetaFileRecord failed\n"); + record->iType = recordType; + record->nSize = dataSize + 8; + memcpy(record->dParm, data, dataSize);
- heap_free(record); - } - else - return OutOfMemory; + if(PlayEnhMetaFileRecord(metafile->playback_dc, metafile->handle_table, + record, metafile->handle_count) == 0) + ERR("PlayEnhMetaFileRecord failed\n");
- break; - } + heap_free(record); } + else + return OutOfMemory; } } else @@ -3496,6 +3409,7 @@ GpStatus WINGDIPAPI GdipEnumerateMetafileSrcRectDestPoints(GpGraphics *graphics, GpMetafile *real_metafile = (GpMetafile*)metafile; /* whoever made this const was joking */ GraphicsContainer state; GpPath *dst_path; + RECT dst_bounds;
TRACE("(%p,%p,%p,%i,%p,%i,%p,%p,%p)\n", graphics, metafile, destPoints, count, srcRect, srcUnit, callback, callbackData, @@ -3585,13 +3499,19 @@ GpStatus WINGDIPAPI GdipEnumerateMetafileSrcRectDestPoints(GpGraphics *graphics, stat = METAFILE_PlaybackUpdateClip(real_metafile); }
- if (stat == Ok && (metafile->metafile_type == MetafileTypeEmf || - metafile->metafile_type == MetafileTypeWmfPlaceable || - metafile->metafile_type == MetafileTypeWmf)) + if (stat == Ok) + { stat = METAFILE_PlaybackGetDC(real_metafile);
+ dst_bounds.left = real_metafile->playback_points[0].X; + dst_bounds.right = real_metafile->playback_points[1].X; + dst_bounds.top = real_metafile->playback_points[0].Y; + dst_bounds.bottom = real_metafile->playback_points[2].Y; + } + if (stat == Ok) - EnumEnhMetaFile(0, metafile->hemf, enum_metafile_proc, &data, NULL); + EnumEnhMetaFile(real_metafile->playback_dc, metafile->hemf, enum_metafile_proc, + &data, &dst_bounds);
METAFILE_PlaybackReleaseDC(real_metafile);
diff --git a/dlls/gdiplus/tests/metafile.c b/dlls/gdiplus/tests/metafile.c index c8bb89a776..f3b817b3de 100644 --- a/dlls/gdiplus/tests/metafile.c +++ b/dlls/gdiplus/tests/metafile.c @@ -2933,7 +2933,7 @@ static void test_restoredc(void)
stat = GdipBitmapGetPixel(bitmap, 21, 21, &color); expect(Ok, stat); - todo_wine expect(0xff0000ff, color); + expect(0xff0000ff, color);
stat = GdipBitmapGetPixel(bitmap, 41, 41, &color); expect(Ok, stat); @@ -2941,7 +2941,7 @@ static void test_restoredc(void)
stat = GdipBitmapGetPixel(bitmap, 61, 61, &color); expect(Ok, stat); - todo_wine expect(0xff0000ff, color); + expect(0xff0000ff, color);
stat = GdipDeleteGraphics(graphics); expect(Ok, stat);
Signed-off-by: Esme Povirk esme@codeweavers.com
Forgot to note, this will break in win9x mode. That might be OK, since gdiplus didn't exist in win9x.
Signed-off-by: Shawn M. Chapla schapla@codeweavers.com --- dlls/gdiplus/tests/graphics.c | 140 +++++++++++++++++++++++++++++++++- 1 file changed, 138 insertions(+), 2 deletions(-)
diff --git a/dlls/gdiplus/tests/graphics.c b/dlls/gdiplus/tests/graphics.c index da15392732..ff43ebf959 100644 --- a/dlls/gdiplus/tests/graphics.c +++ b/dlls/gdiplus/tests/graphics.c @@ -6792,7 +6792,7 @@ static void test_hdc_caching(void) DeleteObject(hbm); }
-static void test_gdi_interop(void) +static void test_gdi_interop_bitmap(void) { GpBitmap *bitmap; GpGraphics *graphics; @@ -6883,6 +6883,141 @@ static void test_gdi_interop(void) expect(Ok, stat); }
+static void test_gdi_interop_hdc(void) +{ + BITMAPINFO bmi; + GpBrush *brush; + GpGraphics *graphics; + GpMatrix *transform; + GpStatus stat; + HBITMAP hbm; + HBRUSH hbrush, holdbrush; + HDC gdi_hdc; + HDC src_hdc; + ULONG *bits; + XFORM xform = { 1.0, 0.0, 0.0, 1.0, 0.0, 0.0 }; + + src_hdc = CreateCompatibleDC(0); + ok(src_hdc != NULL, "CreateCompatibleDC failed\n"); + + bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader); + bmi.bmiHeader.biHeight = -100; + bmi.bmiHeader.biWidth = 100; + bmi.bmiHeader.biBitCount = 32; + bmi.bmiHeader.biPlanes = 1; + bmi.bmiHeader.biCompression = BI_RGB; + bmi.bmiHeader.biClrUsed = 0; + bmi.bmiHeader.biClrImportant = 0; + + hbm = CreateDIBSection(src_hdc, &bmi, DIB_RGB_COLORS, (void**)&bits, NULL, 0); + ok(hbm != NULL, "CreateDIBSection failed\n"); + + SelectObject(src_hdc, hbm); + + SetGraphicsMode(src_hdc, GM_ADVANCED); + + xform.eDx = 10.0; + xform.eDy = 10.0; + SetWorldTransform(src_hdc, &xform); + + stat = GdipCreateFromHDC(src_hdc, &graphics); + expect(Ok, stat); + + stat = GdipCreateMatrix(&transform); + expect(Ok, stat); + + stat = GdipSetMatrixElements(transform, 1.0, 0.0, 0.0, 1.0, 40.0, 40.0); + expect(Ok, stat); + + /* GDI+: Set world transform. Should not matter to GDI. */ + stat = GdipSetWorldTransform(graphics, transform); + expect(Ok, stat); + + stat = GdipGetDC(graphics, &gdi_hdc); + expect(Ok, stat); + expect(gdi_hdc, src_hdc); + + /* GDI: Set GDI transform back to (0, 0). + Should not matter to GDI+. */ + xform.eDx = 0.0; + xform.eDy = 0.0; + SetWorldTransform(gdi_hdc, &xform); + + hbrush = CreateSolidBrush(0xff00aa); + + holdbrush = SelectObject(gdi_hdc, hbrush); + + /* GDI: Draw a rectangle at physical coords (5, 5) to (12, 10). */ + Rectangle(gdi_hdc, 5, 5, 12, 10); + + holdbrush = SelectObject(gdi_hdc, holdbrush); + + /* GDI: Set GDI transform to translate (+20, +20). + Should not matter to GDI+. */ + xform.eDx = 20.0; + xform.eDy = 20.0; + SetWorldTransform(gdi_hdc, &xform); + + GdipReleaseDC(graphics, gdi_hdc); + + /* GDI world transform should still be intact, even when back + in GDI+ mode. */ + stat = GetWorldTransform(src_hdc, &xform); + expect(TRUE, stat); + expect(20.0, xform.eDx); + expect(20.0, xform.eDy); + + stat = GdipCreateSolidFill((ARGB)0xffaa00ff, (GpSolidFill**)&brush); + expect(Ok, stat); + + /* GDI+: Draw a rectangle at physical coords (85, 85) to (88, 95). + The fact that the GDI world transform has been updated should + not influence the GDI+ world transform. GDI+ should still apply + the world transform from the when HDC backed graphics object was + instantiated. */ + stat = GdipFillRectangleI(graphics, brush, 35, 35, 3, 10); + expect(Ok, stat); + + stat = GdipDeleteBrush(brush); + expect(Ok, stat); + + stat = GdipGetDC(graphics, &gdi_hdc); + expect(Ok, stat); + + holdbrush = SelectObject(gdi_hdc, hbrush); + + /* GDI: Draw a rectangle at physical coords (25, 25) to (30, 34). + Updated transform should still be in effect. */ + Rectangle(gdi_hdc, 5, 5, 10, 14); + + SelectObject(gdi_hdc, holdbrush); + + stat = GdipReleaseDC(graphics, gdi_hdc); + expect(Ok, stat); + + GdipDeleteGraphics(graphics); + stat = GdipDeleteMatrix(transform); + expect(Ok, stat); + + holdbrush = SelectObject(src_hdc, hbrush); + + /* GDI: Draw a rectangle at physical coords (35, 35) to (40, 38). + Updated transform should still be in effect on src_hdc. */ + Rectangle(gdi_hdc, 15, 15, 20, 18); + + SelectObject(gdi_hdc, holdbrush); + + DeleteObject(hbrush); + + expect(0x00aa00ff, bits[6 * 100 + 6]); + expect(0x00aa00ff, bits[26 * 100 + 26]); + expect(0x00aa00ff, bits[36 * 100 + 36]); + todo_wine expect(0xffaa00ff, bits[86 * 100 + 86]); + + DeleteDC(src_hdc); + DeleteObject(hbm); +} + START_TEST(graphics) { struct GdiplusStartupInput gdiplusStartupInput; @@ -6976,7 +7111,8 @@ START_TEST(graphics) test_GdipGraphicsSetAbort(); test_cliphrgn_transform(); test_hdc_caching(); - test_gdi_interop(); + test_gdi_interop_bitmap(); + test_gdi_interop_hdc();
GdiplusShutdown(gdiplusToken); DestroyWindow( hwnd );
Signed-off-by: Esme Povirk esme@codeweavers.com
Signed-off-by: Shawn M. Chapla schapla@codeweavers.com --- v2: - Remove a stray newline.
dlls/gdiplus/graphics.c | 1 + dlls/gdiplus/tests/graphics.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/dlls/gdiplus/graphics.c b/dlls/gdiplus/graphics.c index 3c5e25ec41..6c50d2d56c 100644 --- a/dlls/gdiplus/graphics.c +++ b/dlls/gdiplus/graphics.c @@ -6789,6 +6789,7 @@ GpStatus gdi_transform_acquire(GpGraphics *graphics) if (graphics->gdi_transform_acquire_count == 0 && graphics->hdc) { graphics->gdi_transform_save = SaveDC(graphics->hdc); + ModifyWorldTransform(graphics->hdc, NULL, MWT_IDENTITY); SetGraphicsMode(graphics->hdc, GM_COMPATIBLE); SetMapMode(graphics->hdc, MM_TEXT); SetWindowOrgEx(graphics->hdc, 0, 0, NULL); diff --git a/dlls/gdiplus/tests/graphics.c b/dlls/gdiplus/tests/graphics.c index ff43ebf959..15cbcaeaa0 100644 --- a/dlls/gdiplus/tests/graphics.c +++ b/dlls/gdiplus/tests/graphics.c @@ -7012,7 +7012,7 @@ static void test_gdi_interop_hdc(void) expect(0x00aa00ff, bits[6 * 100 + 6]); expect(0x00aa00ff, bits[26 * 100 + 26]); expect(0x00aa00ff, bits[36 * 100 + 36]); - todo_wine expect(0xffaa00ff, bits[86 * 100 + 86]); + expect(0xffaa00ff, bits[86 * 100 + 86]);
DeleteDC(src_hdc); DeleteObject(hbm);
Signed-off-by: Esme Povirk esme@codeweavers.com