[PATCH 1/2] gdi32: Implement recording of the GradientFill EMF record.
Huw Davies
huw at codeweavers.com
Fri Apr 8 05:40:56 CDT 2016
Signed-off-by: Huw Davies <huw at codeweavers.com>
---
dlls/gdi32/enhmfdrv/enhmetafiledrv.h | 2 +
dlls/gdi32/enhmfdrv/graphics.c | 54 +++++++++++++++++++++++
dlls/gdi32/enhmfdrv/init.c | 2 +-
dlls/gdi32/tests/metafile.c | 83 ++++++++++++++++++++++++++++++++++++
4 files changed, 140 insertions(+), 1 deletion(-)
diff --git a/dlls/gdi32/enhmfdrv/enhmetafiledrv.h b/dlls/gdi32/enhmfdrv/enhmetafiledrv.h
index cbd7368..721c82f 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 d3b3325..ae05378 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 34b3de6..e0cbcae 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 5b3bd9f..68ac425 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();
--
2.8.0
More information about the wine-patches
mailing list