[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