diff --git a/dlls/gdi32/enhmfdrv/enhmetafiledrv.h b/dlls/gdi32/enhmfdrv/enhmetafiledrv.h index cbd73681ca0..721c82fee9a 100644 --- a/dlls/gdi32/enhmfdrv/enhmetafiledrv.h +++ b/dlls/gdi32/enhmfdrv/enhmetafiledrv.h @@ -75,6 +75,8 @@ extern BOOL EMFDRV_FlattenPath( PHYSDEV dev ) DECLSPEC_HIDDEN; extern BOOL EMFDRV_FrameRgn( PHYSDEV dev, HRGN hrgn, HBRUSH hbrush, INT width, INT height ) DECLSPEC_HIDDEN; extern BOOL EMFDRV_GdiComment( PHYSDEV dev, UINT bytes, const BYTE *buffer ) DECLSPEC_HIDDEN; extern INT EMFDRV_GetDeviceCaps( PHYSDEV dev, INT cap ) DECLSPEC_HIDDEN; +extern BOOL EMFDRV_GradientFill( PHYSDEV dev, TRIVERTEX *vert_array, ULONG nvert, + void *grad_array, ULONG ngrad, ULONG mode ) DECLSPEC_HIDDEN; extern INT EMFDRV_IntersectClipRect( PHYSDEV dev, INT left, INT top, INT right, INT bottom ) DECLSPEC_HIDDEN; extern BOOL EMFDRV_InvertRgn( PHYSDEV dev, HRGN hrgn ) DECLSPEC_HIDDEN; extern BOOL EMFDRV_LineTo( PHYSDEV dev, INT x, INT y ) DECLSPEC_HIDDEN; diff --git a/dlls/gdi32/enhmfdrv/graphics.c b/dlls/gdi32/enhmfdrv/graphics.c index d3b332589c3..ae053783c8c 100644 --- a/dlls/gdi32/enhmfdrv/graphics.c +++ b/dlls/gdi32/enhmfdrv/graphics.c @@ -855,3 +855,57 @@ no_bounds: HeapFree( GetProcessHeap(), 0, pemr ); return ret; } + +/********************************************************************** + * EMFDRV_GradientFill + */ +BOOL EMFDRV_GradientFill( PHYSDEV dev, TRIVERTEX *vert_array, ULONG nvert, + void *grad_array, ULONG ngrad, ULONG mode ) +{ + EMRGRADIENTFILL *emr; + ULONG i, pt, size, num_pts = ngrad * (mode == GRADIENT_FILL_TRIANGLE ? 3 : 2); + const ULONG *pts = (const ULONG *)grad_array; + BOOL ret; + + size = FIELD_OFFSET(EMRGRADIENTFILL, Ver[nvert]) + num_pts * sizeof(pts[0]); + + emr = HeapAlloc( GetProcessHeap(), 0, size ); + if (!emr) return FALSE; + + for (i = 0; i < num_pts; i++) + { + pt = pts[i]; + + if (i == 0) + { + emr->rclBounds.left = emr->rclBounds.right = vert_array[pt].x; + emr->rclBounds.top = emr->rclBounds.bottom = vert_array[pt].y; + } + else + { + if (vert_array[pt].x < emr->rclBounds.left) + emr->rclBounds.left = vert_array[pt].x; + else if (vert_array[pt].x > emr->rclBounds.right) + emr->rclBounds.right = vert_array[pt].x; + if (vert_array[pt].y < emr->rclBounds.top) + emr->rclBounds.top = vert_array[pt].y; + else if (vert_array[pt].y > emr->rclBounds.bottom) + emr->rclBounds.bottom = vert_array[pt].y; + } + } + emr->rclBounds.right--; + emr->rclBounds.bottom--; + + emr->emr.iType = EMR_GRADIENTFILL; + emr->emr.nSize = size; + emr->nVer = nvert; + emr->nTri = ngrad; + emr->ulMode = mode; + memcpy( emr->Ver, vert_array, nvert * sizeof(vert_array[0]) ); + memcpy( emr->Ver + nvert, pts, num_pts * sizeof(pts[0]) ); + + EMFDRV_UpdateBBox( dev, &emr->rclBounds ); + ret = EMFDRV_WriteRecord( dev, &emr->emr ); + HeapFree( GetProcessHeap(), 0, emr ); + return ret; +} diff --git a/dlls/gdi32/enhmfdrv/init.c b/dlls/gdi32/enhmfdrv/init.c index 34b3de68c2d..e0cbcae2d3d 100644 --- a/dlls/gdi32/enhmfdrv/init.c +++ b/dlls/gdi32/enhmfdrv/init.c @@ -92,7 +92,7 @@ static const struct gdi_dc_funcs EMFDRV_Funcs = NULL, /* pGetTextExtentExPointI */ NULL, /* pGetTextFace */ NULL, /* pGetTextMetrics */ - NULL, /* pGradientFill */ + EMFDRV_GradientFill, /* pGradientFill */ EMFDRV_IntersectClipRect, /* pIntersectClipRect */ EMFDRV_InvertRgn, /* pInvertRgn */ EMFDRV_LineTo, /* pLineTo */ diff --git a/dlls/gdi32/tests/metafile.c b/dlls/gdi32/tests/metafile.c index 5b3bd9fbb60..68ac425315d 100644 --- a/dlls/gdi32/tests/metafile.c +++ b/dlls/gdi32/tests/metafile.c @@ -1424,6 +1424,44 @@ static const unsigned char EMF_POLYPOLYLINE_BITS[] = 0x14, 0x00, 0x00, 0x00 }; +static const unsigned char EMF_GRADIENTFILL_BITS[] = +{ + 0x01, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x2b, 0x01, 0x00, 0x00, 0x35, 0x01, 0x00, 0x00, + 0x23, 0x00, 0x00, 0x00, 0x61, 0x01, 0x00, 0x00, + 0x31, 0x29, 0x00, 0x00, 0xa3, 0x2a, 0x00, 0x00, + 0x20, 0x45, 0x4d, 0x46, 0x00, 0x00, 0x01, 0x00, + 0x0c, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x05, 0x00, 0x00, 0x46, 0x03, 0x00, 0x00, + 0xda, 0x01, 0x00, 0x00, 0x28, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x15, 0x3c, 0x07, 0x00, + 0xcb, 0x82, 0x04, 0x00, 0x76, 0x00, 0x00, 0x00, + 0x8c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x2b, 0x01, 0x00, 0x00, + 0x35, 0x01, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x00, 0xff, 0x00, 0x80, 0x00, 0x00, 0x01, 0x80, + 0xc8, 0x00, 0x00, 0x00, 0xd2, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, + 0xb4, 0x00, 0x00, 0x00, 0xbe, 0x00, 0x00, 0x00, + 0x34, 0x12, 0x78, 0x56, 0xbc, 0x9a, 0xf0, 0xde, + 0x2c, 0x01, 0x00, 0x00, 0x36, 0x01, 0x00, 0x00, + 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, + 0x90, 0x01, 0x00, 0x00, 0x9a, 0x01, 0x00, 0x00, + 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0e, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00 +}; + /* For debugging or dumping the raw metafiles produced by * new test functions. */ @@ -3599,6 +3637,50 @@ static void test_emf_PolyPolyline(void) DeleteEnhMetaFile(hemf); } +static void test_emf_GradientFill(void) +{ + HDC mf; + HENHMETAFILE hemf; + TRIVERTEX v[] = + { + { 1, 10, 0xff00, 0x8000, 0x0000, 0x8001 }, + { 200, 210, 0x0000, 0x0000, 0xff00, 0xff00 }, + { 180, 190, 0x1234, 0x5678, 0x9abc, 0xdef0 }, + { 300, 310, 0xff00, 0xff00, 0xff00, 0x0000 }, + { 400, 410, 0xff00, 0xff00, 0xff00, 0x0000 } + }; + GRADIENT_TRIANGLE tri[] = { { 0, 1, 2 }, { 3, 1, 0 } }; + BOOL ret; + + mf = CreateEnhMetaFileA( GetDC( 0 ), NULL, NULL, NULL ); + ok( mf != 0, "CreateEnhMetaFileA error %d\n", GetLastError() ); + + /* Don't test the GRADIENT_FILL_RECT_ modes since a Windows bug + * means it allocates three mesh indicies rather than two per + * rectangle. This results in uninitialised values being written + * to the EMF which is rather difficult to test against. + * + * Note also that the final vertex here is not required, yet it is + * written to the EMF, but is not considered in the bounds + * calculation. + */ + ret = GdiGradientFill( mf, v, sizeof(v) / sizeof(v[0]), tri, sizeof(tri) / sizeof(tri[0]), + GRADIENT_FILL_TRIANGLE ); + ok( ret, "GradientFill\n" ); + + hemf = CloseEnhMetaFile( mf ); + ok( hemf != 0, "CloseEnhMetaFile error %d\n", GetLastError() ); + + if (compare_emf_bits( hemf, EMF_GRADIENTFILL_BITS, sizeof(EMF_GRADIENTFILL_BITS), + "emf_GradientFill", FALSE ) != 0) + { + dump_emf_bits( hemf, "emf_GradientFill" ); + dump_emf_records( hemf, "emf_GradientFill" ); + } + + DeleteEnhMetaFile( hemf ); +} + START_TEST(metafile) { init_function_pointers(); @@ -3614,6 +3696,7 @@ START_TEST(metafile) test_emf_polybezier(); test_emf_GetPath(); test_emf_PolyPolyline(); + test_emf_GradientFill(); /* For win-format metafiles (mfdrv) */ test_mf_SaveDC();