[PATCH v2] gdi32/tests: Add tests for the advanced graphics mode

Ralf Habacker ralf.habacker at freenet.de
Tue Feb 9 02:17:59 CST 2021


Because drawing simple lines already gives different results than a
native Windows, the comparison of hashes does not work anymore.

Therefore, the tests associated to advanced graphics mode creates
bitmap files for each processed test in the current directoy, which
can then be compared visually.

Signed-off-by: Ralf Habacker <ralf.habacker at freenet.de>
---
 dlls/gdi32/tests/dib.c | 242 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 242 insertions(+)

diff --git a/dlls/gdi32/tests/dib.c b/dlls/gdi32/tests/dib.c
index bdc3d9ed55b..3e48694f143 100644
--- a/dlls/gdi32/tests/dib.c
+++ b/dlls/gdi32/tests/dib.c
@@ -3529,11 +3529,253 @@ static void test_simple_graphics(void)
     DeleteDC(mem_dc);
 }
 
+/* Comparing hashes does not work because drawing simple lines is already different from native win32 */
+/* #define WITH_HASH */
+
+typedef struct {
+    HDC dc;
+    BITMAPINFO *bmi;
+    BYTE *bits;
+    HBITMAP dib;
+#ifdef WITH_HASH
+    char *hash_dib;
+#endif
+    char test_name[1024];
+    char save_path[MAX_PATH];
+    char hash_name[1024];
+    RECT bounds;
+    double angle;
+    double shearX;
+} test_data;
+
+static test_data _test_data;
+test_data *td = &_test_data;
+
+double radians ( double d )
+{
+    return d * M_PI / 180;
+}
+
+BOOL save_bitmap_to_file(HBITMAP hBitmap, LPSTR lpszFileName)
+{
+    HDC hDC;
+    int iBits;
+    WORD wBitCount;
+    DWORD dwPaletteSize = 0, dwBmBitsSize = 0, dwDIBSize = 0, dwWritten = 0;
+    BITMAP Bitmap0;
+    BITMAPFILEHEADER bmfHdr;
+    BITMAPINFOHEADER bi;
+    LPBITMAPINFOHEADER lpbi;
+    HANDLE fh, hDib, hPal, hOldPal2 = NULL;
+    hDC = CreateDCA("DISPLAY", NULL, NULL, NULL);
+    iBits = GetDeviceCaps(hDC, BITSPIXEL) * GetDeviceCaps(hDC, PLANES);
+    DeleteDC(hDC);
+    if (iBits <= 1)
+        wBitCount = 1;
+    else if (iBits <= 4)
+        wBitCount = 4;
+    else if (iBits <= 8)
+        wBitCount = 8;
+    else
+        wBitCount = 24;
+    GetObjectA(hBitmap, sizeof(Bitmap0), (LPSTR)&Bitmap0);
+    bi.biSize = sizeof(BITMAPINFOHEADER);
+    bi.biWidth = Bitmap0.bmWidth;
+    bi.biHeight = -Bitmap0.bmHeight;
+    bi.biPlanes = 1;
+    bi.biBitCount = wBitCount;
+    bi.biCompression = BI_RGB;
+    bi.biSizeImage = 0;
+    bi.biXPelsPerMeter = 0;
+    bi.biYPelsPerMeter = 0;
+    bi.biClrImportant = 0;
+    bi.biClrUsed = 256;
+    dwBmBitsSize = ((Bitmap0.bmWidth * wBitCount + 31) & ~31) / 8
+        * Bitmap0.bmHeight;
+    hDib = GlobalAlloc(GHND, dwBmBitsSize + dwPaletteSize + sizeof(BITMAPINFOHEADER));
+    lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDib);
+    *lpbi = bi;
+
+    hPal = GetStockObject(DEFAULT_PALETTE);
+    if (hPal)
+    {
+        hDC = GetDC(NULL);
+        hOldPal2 = SelectPalette(hDC, (HPALETTE)hPal, FALSE);
+        RealizePalette(hDC);
+    }
+
+
+    GetDIBits(hDC, hBitmap, 0, (UINT)Bitmap0.bmHeight, (LPSTR)lpbi + sizeof(BITMAPINFOHEADER)
+        + dwPaletteSize, (BITMAPINFO *)lpbi, DIB_RGB_COLORS);
+
+    if (hOldPal2)
+    {
+        SelectPalette(hDC, (HPALETTE)hOldPal2, TRUE);
+        RealizePalette(hDC);
+        ReleaseDC(NULL, hDC);
+    }
+
+    fh = CreateFileA(lpszFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
+        FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
+
+    if (fh == INVALID_HANDLE_VALUE)
+        return FALSE;
+
+    bmfHdr.bfType = 0x4D42; // "BM"
+    dwDIBSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + dwPaletteSize + dwBmBitsSize;
+    bmfHdr.bfSize = dwDIBSize;
+    bmfHdr.bfReserved1 = 0;
+    bmfHdr.bfReserved2 = 0;
+    bmfHdr.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + (DWORD)sizeof(BITMAPINFOHEADER) + dwPaletteSize;
+
+    WriteFile(fh, (LPSTR)&bmfHdr, sizeof(BITMAPFILEHEADER), &dwWritten, NULL);
+
+    WriteFile(fh, (LPSTR)lpbi, dwDIBSize, &dwWritten, NULL);
+    GlobalUnlock(hDib);
+    GlobalFree(hDib);
+    CloseHandle(fh);
+    return TRUE;
+}
+
+void set_transform( HDC dc, RECT *bounds, double angle )
+{
+    XFORM xf;
+    double r = radians( angle );
+    xf.eM11 = cos( r ) + sin( r ) * td->shearX;
+    xf.eM22 = cos( r );
+    xf.eM12 = -sin( r );
+    xf.eM21 = sin( r ) + cos( r ) * td->shearX;
+    xf.eDx = ( bounds->right - bounds->left ) / 4;
+    xf.eDy = ( bounds->bottom - bounds->top ) / 4;
+    SetWorldTransform( dc, &xf );
+}
+
+
+void init( test_data *td, const char *test_name )
+{
+    sprintf( td->test_name, "%s", test_name );
+    sprintf( td->save_path, "%s-%3.1f-%2.1f.bmp", td->test_name, td->shearX, td->angle );
+    sprintf( td->hash_name, "sha1_advanced_%s_%3.1f_%2.1f", td->test_name, td->shearX, td->angle );
+    trace( "%s\n", td->test_name );
+    reset_bits( td->dc, td->bmi, td->bits );
+    MoveToEx( td->dc, -5, 0, NULL );
+    LineTo( td->dc, 5, 0 );
+    MoveToEx( td->dc, 0, 5, NULL );
+    LineTo( td->dc, 0, -5 );
+}
+
+void check_hash( test_data *td )
+{
+#ifdef WITH_HASH
+    if ( td->hash_dib )
+        HeapFree( GetProcessHeap(), 0, td->hash_dib );
+    td->hash_dib = hash_dib( td->dc, td->bmi, td->bits );
+    printf( "const char *%s = \"%s\";\n", td->hash_name, td->hash_dib );
+#endif
+    // instead we dump the display to a file for visual inspection
+    save_bitmap_to_file( td->dib, td->save_path );
+}
+
+static void test_gdi( double angle, double shearX )
+{
+    char bmibuf[sizeof( BITMAPINFO ) + 256 * sizeof( RGBQUAD )];
+    HBITMAP orig_bm;
+    HPALETTE default_palette, old_hpal;
+    RECT r;
+
+    td->bmi = ( BITMAPINFO * )bmibuf;
+    td->dc = CreateCompatibleDC( NULL );
+    td->angle = angle;
+    td->shearX = shearX;
+
+    SetGraphicsMode( td->dc, GM_ADVANCED );
+    set_transform( td->dc, &td->bounds, td->angle );
+
+    memset( td->bmi, 0, sizeof( bmibuf ));
+    td->bmi->bmiHeader.biSize = sizeof( td->bmi->bmiHeader );
+    td->bmi->bmiHeader.biHeight = td->bounds.right;
+    td->bmi->bmiHeader.biWidth = td->bounds.bottom;
+    td->bmi->bmiHeader.biBitCount = 32;
+    td->bmi->bmiHeader.biPlanes = 1;
+    td->bmi->bmiHeader.biCompression = BI_RGB;
+
+    td->dib = CreateDIBSection( 0, td->bmi, DIB_RGB_COLORS, ( void** )&( td->bits ), NULL, 0 );
+    orig_bm = SelectObject( td->dc, td->dib );
+
+    default_palette = create_default_palette( 8 );
+    old_hpal = SelectPalette( td->dc, default_palette, FALSE );
+
+    current_bounds = &td->bounds;
+    SetBoundsRect( td->dc, &td->bounds, DCB_SET );
+
+    SetRect( &r, 0, 0, 128, 128 );
+
+    init( td, "LineTo" );
+    MoveToEx( td->dc, r.left, r.top, NULL );
+    LineTo( td->dc, r.right, r.bottom );
+    check_hash( td );
+
+    init( td, "Rectangle" );
+    ok( Rectangle( td->dc, r.left, r.top, r.right, r.bottom ), td->test_name );
+    check_hash( td );
+
+    init( td, "Ellipse" );
+    ok( Ellipse( td->dc, r.left, r.top, r.right, r.bottom ), td->test_name );
+    check_hash( td );
+
+    init( td, "Arc" );
+    ok( Arc( td->dc, r.left, r.top, r.right, r.bottom, r.left+10, r.top, r.right-10, r.bottom ), td->test_name );
+    check_hash( td );
+
+    init( td, "ArcTo" );
+    ok( ArcTo( td->dc, r.left, r.top, r.right, r.bottom, r.left+10, r.top, r.right-10, r.bottom ), td->test_name );
+    check_hash( td );
+
+    init( td, "Chord" );
+    ok( Chord( td->dc, r.left, r.top, r.right, r.bottom, r.left+10, r.top, r.right-10, r.bottom ), td->test_name );
+    check_hash( td );
+
+    init( td, "Pie" );
+    ok( Pie( td->dc, r.left, r.top, r.right, r.bottom, r.left+10, r.top, r.right-10, r.bottom ), td->test_name );
+    check_hash( td );
+
+    init( td, "FillRect" );
+    ok( FillRect( td->dc, &r, GetStockObject( WHITE_BRUSH )), td->test_name );
+    check_hash( td );
+
+    SelectObject( td->dc, orig_bm );
+    DeleteObject( td->dib );
+    SelectPalette( td->dc, old_hpal, FALSE );
+    DeleteDC( td->dc );
+}
+
+static void test_advanced_graphics( void )
+{
+    td->bounds.left = 0;
+    td->bounds.top = 0;
+    td->bounds.right = 256;
+    td->bounds.bottom = 256;
+
+    test_gdi( 0, 0.0 );
+    test_gdi( 30, 0.0 );
+    test_gdi( 60, 0.0 );
+    test_gdi( 90, 0.0 );
+    test_gdi( 120, 0.0 );
+    test_gdi( 150, 0.0 );
+    test_gdi( 0, 0.1 );
+    test_gdi( 30, 0.1 );
+    test_gdi( 60, 0.1 );
+    test_gdi( 90, 0.1 );
+    test_gdi( 120, 0.1 );
+    test_gdi( 150, 0.1 );
+}
+
 START_TEST(dib)
 {
     CryptAcquireContextW(&crypt_prov, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);
 
     test_simple_graphics();
+    test_advanced_graphics();
 
     CryptReleaseContext(crypt_prov, 0);
 }
-- 
2.26.2




More information about the wine-devel mailing list