gdi32: Implement recording of the GradientFill EMF record.

Signed-off-by: Huw Davies <huw@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Huw Davies 2016-04-08 11:40:56 +01:00 committed by Alexandre Julliard
parent 4161f5120b
commit ac0959cdf6
4 changed files with 140 additions and 1 deletions

View File

@ -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;

View File

@ -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;
}

View File

@ -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 */

View File

@ -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();