/*
 * WoW64 GDI functions
 *
 * Copyright 2021 Jacek Caban for CodeWeavers
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 */

#include <stdarg.h>

#include "ntstatus.h"
#define WIN32_NO_STATUS
#include "windef.h"
#include "winbase.h"
#include "ntgdi.h"
#include "wow64win_private.h"

NTSTATUS WINAPI wow64_NtGdiCreateClientObj( UINT *args )
{
    ULONG type = get_ulong( &args );

    return HandleToUlong( NtGdiCreateClientObj( type ));
}

NTSTATUS WINAPI wow64_NtGdiDeleteClientObj( UINT *args )
{
    HGDIOBJ obj = get_handle( &args );

    return NtGdiDeleteClientObj( obj );
}

NTSTATUS WINAPI wow64_NtGdiExtGetObjectW( UINT *args )
{
    HGDIOBJ handle = get_handle( &args );
    INT count = get_ulong( &args );
    void *buffer = get_ptr( &args );

    return NtGdiExtGetObjectW( handle, count, buffer );
}

NTSTATUS WINAPI wow64_NtGdiGetDCObject( UINT *args )
{
    HDC hdc = get_handle( &args );
    UINT type = get_ulong( &args );

    return HandleToUlong( NtGdiGetDCObject( hdc, type ));
}

NTSTATUS WINAPI wow64_NtGdiCreateBitmap( UINT *args )
{
    INT width = get_ulong( &args );
    INT height = get_ulong( &args );
    UINT planes = get_ulong( &args );
    UINT bpp = get_ulong( &args );
    const void *bits = get_ptr( &args );

    return HandleToUlong( NtGdiCreateBitmap( width, height, planes, bpp, bits ));
}

NTSTATUS WINAPI wow64_NtGdiGetBitmapBits( UINT *args )
{
    HBITMAP bitmap = get_handle( &args );
    LONG count = get_ulong( &args );
    void *bits = get_ptr( &args );

    return NtGdiGetBitmapBits( bitmap, count, bits );
}

NTSTATUS WINAPI wow64_NtGdiSetBitmapBits( UINT *args )
{
    HBITMAP hbitmap = get_handle( &args );
    LONG count = get_ulong( &args );
    const void *bits = get_ptr( &args );

    return NtGdiSetBitmapBits( hbitmap, count, bits );
}

NTSTATUS WINAPI wow64_NtGdiGetBitmapDimension( UINT *args )
{
    HBITMAP bitmap = get_handle( &args );
    SIZE *size = get_ptr( &args );

    return NtGdiGetBitmapDimension( bitmap, size );
}

NTSTATUS WINAPI wow64_NtGdiSetBitmapDimension( UINT *args )
{
    HBITMAP hbitmap = get_handle( &args );
    INT x = get_ulong( &args );
    INT y = get_ulong( &args );
    SIZE *prev_size = get_ptr( &args );

    return NtGdiSetBitmapDimension( hbitmap, x, y, prev_size );
}

NTSTATUS WINAPI wow64_NtGdiCreateDIBSection( UINT *args )
{
    HDC hdc = get_handle( &args );
    HANDLE section = get_handle( &args );
    DWORD offset = get_ulong( &args );
    const BITMAPINFO *bmi = get_ptr( &args );
    UINT usage = get_ulong( &args );
    UINT header_size = get_ulong( &args );
    ULONG flags = get_ulong( &args );
    ULONG_PTR color_space = get_ulong( &args );
    void *bits32 = get_ptr( &args );

    void *bits;
    HBITMAP ret;

    ret = NtGdiCreateDIBSection( hdc, section, offset, bmi, usage, header_size,
                                 flags, color_space, addr_32to64( &bits, bits32 ));
    if (ret) put_addr( bits32, bits );
    return HandleToUlong( ret );
}

NTSTATUS WINAPI wow64_NtGdiCreateDIBBrush( UINT *args )
{
    const void *data = get_ptr( &args );
    UINT coloruse = get_ulong( &args );
    UINT size = get_ulong( &args );
    BOOL is_8x8 = get_ulong( &args );
    BOOL pen = get_ulong( &args );
    const void *client = get_ptr( &args );

    return HandleToUlong( NtGdiCreateDIBBrush( data, coloruse, size, is_8x8, pen, client ));
}

NTSTATUS WINAPI wow64_NtGdiCreateHatchBrushInternal( UINT *args )
{
    INT style = get_ulong( &args );
    COLORREF color = get_ulong( &args );
    BOOL pen = get_ulong( &args );

    return HandleToULong( NtGdiCreateHatchBrushInternal( style, color, pen ));
}

NTSTATUS WINAPI wow64_NtGdiCreatePatternBrushInternal( UINT *args )
{
    HBITMAP hbitmap = get_handle( &args );
    BOOL pen = get_ulong( &args );
    BOOL is_8x8 = get_ulong( &args );

    return HandleToUlong( NtGdiCreatePatternBrushInternal( hbitmap, pen, is_8x8 ));
}

NTSTATUS WINAPI wow64_NtGdiCreateSolidBrush( UINT *args )
{
    COLORREF color = get_ulong( &args );
    HBRUSH brush = get_handle( &args );

    return HandleToUlong( NtGdiCreateSolidBrush( color, brush ));
}

NTSTATUS WINAPI wow64_NtGdiCreatePen( UINT *args )
{
    INT style = get_ulong( &args );
    INT width = get_ulong( &args );
    COLORREF color = get_ulong( &args );
    HBRUSH brush = get_handle( &args );

    return HandleToUlong( NtGdiCreatePen( style, width, color, brush ));
}

NTSTATUS WINAPI wow64_NtGdiExtCreatePen( UINT *args )
{
    DWORD style = get_ulong( &args );
    DWORD width = get_ulong( &args );
    ULONG brush_style = get_ulong( &args );
    ULONG color = get_ulong( &args );
    ULONG_PTR client_hatch = get_ulong( &args );
    ULONG_PTR hatch = get_ulong( &args );
    DWORD style_count = get_ulong( &args );
    const DWORD *style_bits = get_ptr( &args );
    ULONG dib_size = get_ulong( &args );
    BOOL old_style = get_ulong( &args );
    HBRUSH brush = get_handle( &args );

    return HandleToUlong( NtGdiExtCreatePen( style, width, brush_style, color, client_hatch,
                                             hatch, style_count, style_bits, dib_size,
                                             old_style, brush ));
}

NTSTATUS WINAPI wow64_NtGdiCreateRectRgn( UINT *args )
{
    INT left = get_ulong( &args );
    INT top = get_ulong( &args );
    INT right = get_ulong( &args );
    INT bottom = get_ulong( &args );

    return HandleToUlong( NtGdiCreateRectRgn( left, top, right, bottom ));
}

NTSTATUS WINAPI wow64_NtGdiCreateRoundRectRgn( UINT *args )
{
    INT left = get_ulong( &args );
    INT top = get_ulong( &args );
    INT right = get_ulong( &args );
    INT bottom = get_ulong( &args );
    INT ellipse_width = get_ulong( &args );
    INT ellipse_height = get_ulong( &args );

    return HandleToUlong( NtGdiCreateRoundRectRgn( left, top, right, bottom,
                                                   ellipse_width, ellipse_height ));
}

NTSTATUS WINAPI wow64_NtGdiCreateEllipticRgn( UINT *args )
{
    INT left = get_ulong( &args );
    INT top = get_ulong( &args );
    INT right = get_ulong( &args );
    INT bottom = get_ulong( &args );

    return HandleToUlong( NtGdiCreateEllipticRgn( left, top, right, bottom ));
}

NTSTATUS WINAPI wow64_NtGdiExtCreateRegion( UINT *args )
{
    const XFORM *xform = get_ptr( &args );
    DWORD count = get_ulong( &args );
    const RGNDATA *data = get_ptr( &args );

    return HandleToUlong( NtGdiExtCreateRegion( xform, count, data ));
}

NTSTATUS WINAPI wow64_NtGdiGetRegionData( UINT *args )
{
    HRGN hrgn = get_ptr( &args );
    DWORD count = get_ulong( &args );
    RGNDATA *data = get_ptr( &args );

    return NtGdiGetRegionData( hrgn, count, data );
}

NTSTATUS WINAPI wow64_NtGdiEqualRgn( UINT *args )
{
    HRGN hrgn1 = get_handle( &args );
    HRGN hrgn2 = get_handle( &args );

    return NtGdiEqualRgn( hrgn1, hrgn2 );
}

NTSTATUS WINAPI wow64_NtGdiGetRgnBox( UINT *args )
{
    HRGN hrgn = get_handle( &args );
    RECT *rect = get_ptr( &args );

    return NtGdiGetRgnBox( hrgn, rect );
}

NTSTATUS WINAPI wow64_NtGdiSetRectRgn( UINT *args )
{
    HRGN hrgn = get_handle( &args );
    INT left = get_ulong( &args );
    INT top = get_ulong( &args );
    INT right = get_ulong( &args );
    INT bottom = get_ulong( &args );

    return NtGdiSetRectRgn( hrgn, left, top, right, bottom );
}

NTSTATUS WINAPI wow64_NtGdiOffsetRgn( UINT *args )
{
    HRGN hrgn = get_handle( &args );
    INT x = get_ulong( &args );
    INT y = get_ulong( &args );

    return NtGdiOffsetRgn( hrgn, x, y );
}

NTSTATUS WINAPI wow64_NtGdiCombineRgn( UINT *args )
{
    HRGN dest = get_handle( &args );
    HRGN src1 = get_handle( &args );
    HRGN src2 = get_handle( &args );
    INT mode = get_ulong( &args );

    return NtGdiCombineRgn( dest, src1, src2, mode );
}

NTSTATUS WINAPI wow64_NtGdiPtInRegion( UINT *args )
{
    HRGN hrgn = get_handle( &args );
    INT x = get_ulong( &args );
    INT y = get_ulong( &args );

    return NtGdiPtInRegion( hrgn, x, y );
}

NTSTATUS WINAPI wow64_NtGdiRectInRegion( UINT *args )
{
    HRGN hrgn = get_handle( &args );
    const RECT *rect = get_ptr( &args );

    return NtGdiRectInRegion( hrgn, rect );
}

NTSTATUS WINAPI wow64_NtGdiSetMetaRgn( UINT *args )
{
    HDC hdc = get_handle( &args );

    return NtGdiSetMetaRgn( hdc );
}

NTSTATUS WINAPI wow64_NtGdiSaveDC( UINT *args )
{
    HDC hdc = get_handle( &args );

    return NtGdiSaveDC( hdc );
}

NTSTATUS WINAPI wow64_NtGdiSetBrushOrg( UINT *args )
{
    HDC hdc = get_handle( &args );
    INT x = get_ulong( &args );
    INT y = get_ulong( &args );
    POINT *prev_org = get_ptr( &args );

    return NtGdiSetBrushOrg( hdc, x, y, prev_org );
}

NTSTATUS WINAPI wow64_NtGdiGetTransform( UINT *args )
{
    HDC hdc = get_handle( &args );
    DWORD which = get_ulong( &args );
    XFORM *xform = get_ptr( &args );

    return NtGdiGetTransform( hdc, which, xform );
}

NTSTATUS WINAPI wow64_NtGdiDescribePixelFormat( UINT *args )
{
    HDC hdc = get_handle( &args );
    INT format = get_ulong( &args );
    UINT size = get_ulong( &args );
    PIXELFORMATDESCRIPTOR *descr = get_ptr( &args );

    return NtGdiDescribePixelFormat( hdc, format, size, descr );
}

NTSTATUS WINAPI wow64_NtGdiSetPixelFormat( UINT *args )
{
    HDC hdc = get_handle( &args );
    INT format = get_ulong( &args );

    return NtGdiSetPixelFormat( hdc, format );
}

NTSTATUS WINAPI wow64_NtGdiSwapBuffers( UINT *args )
{
    HDC hdc = get_handle( &args );

    return NtGdiSwapBuffers( hdc );
}

NTSTATUS WINAPI wow64_NtGdiDrawStream( UINT *args )
{
    HDC hdc = get_handle( &args );
    ULONG in = get_ulong( &args );
    void *pvin = get_ptr( &args );

    return NtGdiDrawStream( hdc, in, pvin );
}

NTSTATUS WINAPI wow64_NtGdiSetTextJustification( UINT *args )
{
    HDC hdc = get_handle( &args );
    INT extra = get_ulong( &args );
    INT breaks = get_ulong( &args );

    return NtGdiSetTextJustification( hdc, extra, breaks );
}

NTSTATUS WINAPI wow64_NtGdiHfontCreate( UINT *args )
{
    const ENUMLOGFONTEXDVW *enumex = get_ptr( &args );
    ULONG unk2 = get_ulong( &args );
    ULONG unk3 = get_ulong( &args );
    ULONG unk4 = get_ulong( &args );
    void *data = get_ptr( &args );

    return HandleToUlong( NtGdiHfontCreate( enumex, unk2, unk3, unk4, data ));
}

NTSTATUS WINAPI wow64_NtGdiGetFontFileData( UINT *args )
{
    DWORD instance_id = get_ulong( &args );
    DWORD file_index = get_ulong( &args );
    UINT64 *offset = get_ptr( &args );
    void *buff = get_ptr( &args );
    DWORD buff_size = get_ulong( &args );

    return NtGdiGetFontFileData( instance_id, file_index, offset, buff, buff_size );
}

NTSTATUS WINAPI wow64_NtGdiGetFontFileInfo( UINT *args )
{
    DWORD instance_id = get_ulong( &args );
    DWORD file_index = get_ulong( &args );
    struct font_fileinfo *info = get_ptr( &args );
    SIZE_T size = get_ulong( &args );
    ULONG *needed32 = get_ptr( &args );

    SIZE_T needed;
    BOOL ret;

    ret = NtGdiGetFontFileInfo( instance_id, file_index, info, size, size_32to64( &needed, needed32 ));
    put_size( needed32, needed );
    return ret;
}

NTSTATUS WINAPI wow64_NtGdiAddFontMemResourceEx( UINT *args )
{
    void *ptr = get_ptr( &args );
    DWORD size = get_ulong( &args );
    void *dv = get_ptr( &args );
    ULONG dv_size = get_ulong( &args );
    DWORD *count = get_ptr( &args );

    return HandleToUlong( NtGdiAddFontMemResourceEx( ptr, size, dv, dv_size, count ));
}

NTSTATUS WINAPI wow64_NtGdiAddFontResourceW( UINT *args )
{
    const WCHAR *str = get_ptr( &args );
    ULONG size = get_ulong( &args );
    ULONG files = get_ulong( &args );
    DWORD flags = get_ulong( &args );
    DWORD tid = get_ulong( &args );
    void *dv = get_ptr( &args );

    return NtGdiAddFontResourceW( str, size, files, flags, tid, dv );
}

NTSTATUS WINAPI wow64_NtGdiRemoveFontMemResourceEx( UINT *args )
{
    HANDLE handle = get_handle( &args );

    return NtGdiRemoveFontMemResourceEx( handle );
}

NTSTATUS WINAPI wow64_NtGdiRemoveFontResourceW( UINT *args )
{
    const WCHAR *str = get_ptr( &args );
    ULONG size = get_ulong( &args );
    ULONG files = get_ulong( &args );
    DWORD flags = get_ulong( &args );
    DWORD tid = get_ulong( &args );
    void *dv = get_ptr( &args );

    return NtGdiRemoveFontResourceW( str, size, files, flags, tid, dv );
}

NTSTATUS WINAPI wow64_NtGdiGetColorAdjustment( UINT *args )
{
    HDC hdc = get_handle( &args );
    COLORADJUSTMENT *ca = get_ptr( &args );

    return NtGdiGetColorAdjustment( hdc, ca );
}

NTSTATUS WINAPI wow64_NtGdiSetColorAdjustment( UINT *args )
{
    HDC hdc = get_handle( &args );
    const COLORADJUSTMENT *ca = get_ptr( &args );

    return NtGdiSetColorAdjustment( hdc, ca );
}

NTSTATUS WINAPI wow64_NtGdiSetVirtualResolution( UINT *args )
{
    HDC hdc = get_handle( &args );
    DWORD horz_res = get_ulong( &args );
    DWORD vert_res = get_ulong( &args );
    DWORD horz_size = get_ulong( &args );
    DWORD vert_size = get_ulong( &args );

    return NtGdiSetVirtualResolution( hdc, horz_res, vert_res, horz_size, vert_size );
}

NTSTATUS WINAPI wow64_NtGdiTransformPoints( UINT *args )
{
    HDC hdc = get_handle( &args );
    const POINT *points_in = get_ptr( &args );
    POINT *points_out = get_ptr( &args );
    INT count = get_ulong( &args );
    UINT mode = get_ulong( &args );

    return NtGdiTransformPoints( hdc, points_in, points_out, count, mode );
}

NTSTATUS WINAPI wow64_NtGdiCreatePaletteInternal( UINT *args )
{
    const LOGPALETTE *palette = get_ptr( &args );
    UINT count = get_ulong( &args );

    return HandleToUlong( NtGdiCreatePaletteInternal( palette, count ));
}

NTSTATUS WINAPI wow64_NtGdiCreateHalftonePalette( UINT *args )
{
    HDC hdc = get_handle( &args );

    return HandleToUlong( NtGdiCreateHalftonePalette( hdc ));
}

NTSTATUS WINAPI wow64_NtGdiGetNearestPaletteIndex( UINT *args )
{
    HPALETTE hpalette = get_handle( &args );
    COLORREF color = get_ulong( &args );

    return NtGdiGetNearestPaletteIndex( hpalette, color );
}

NTSTATUS WINAPI wow64_NtGdiGetSystemPaletteUse( UINT *args )
{
    HDC hdc = get_handle( &args );

    return NtGdiGetSystemPaletteUse( hdc );
}

NTSTATUS WINAPI wow64_NtGdiSetMagicColors( UINT *args )
{
    HDC hdc = get_handle( &args );
    DWORD magic = get_ulong( &args );
    ULONG index = get_ulong( &args );

    return NtGdiSetMagicColors( hdc, magic, index );
}

NTSTATUS WINAPI wow64_NtGdiGetPath( UINT *args )
{
    HDC hdc = get_handle( &args );
    POINT *points = get_ptr( &args );
    BYTE *types = get_ptr( &args );
    INT size = get_ulong( &args );

    return NtGdiGetPath( hdc, points, types, size );
}

NTSTATUS WINAPI wow64_NtGdiPathToRegion( UINT *args )
{
    HDC hdc = get_handle( &args );

    return HandleToUlong( NtGdiPathToRegion( hdc ));
}

NTSTATUS WINAPI wow64_NtGdiFlattenPath( UINT *args )
{
    HDC hdc = get_handle( &args );

    return NtGdiFlattenPath( hdc );
}

NTSTATUS WINAPI wow64_NtGdiGetSpoolMessage( UINT *args )
{
    void *ptr1 = get_ptr( &args );
    DWORD data2 = get_ulong( &args );
    void *ptr3 = get_ptr( &args );
    DWORD data4 = get_ulong( &args );

    return NtGdiGetSpoolMessage( ptr1, data2, ptr3, data4 );
}

NTSTATUS WINAPI wow64_NtGdiInitSpool( UINT *args )
{
    return NtGdiInitSpool();
}

NTSTATUS WINAPI wow64_NtGdiFlush( UINT *args )
{
    return NtGdiFlush();
}

NTSTATUS WINAPI wow64_NtGdiDdDDICloseAdapter( UINT *args )
{
    const D3DKMT_CLOSEADAPTER *desc = get_ptr( &args );

    return NtGdiDdDDICloseAdapter( desc );
}

NTSTATUS WINAPI wow64_NtGdiDdDDICreateDevice( UINT *args )
{
    struct
    {
        D3DKMT_HANDLE hAdapter;
        D3DKMT_CREATEDEVICEFLAGS Flags;
        D3DKMT_HANDLE hDevice;
        ULONG pCommandBuffer;
        UINT CommandBufferSize;
        ULONG pAllocationList;
        UINT AllocationListSize;
        ULONG pPatchLocationList;
        UINT PatchLocationListSize;
    } *desc32 = get_ptr( &args );

    D3DKMT_CREATEDEVICE desc =
    {
        { desc32->hAdapter },
        desc32->Flags
    };
    NTSTATUS status;

    if (!(status = NtGdiDdDDICreateDevice( &desc )))
    {
        desc32->hDevice = desc.hDevice;
        desc32->pCommandBuffer = PtrToUlong( desc.pCommandBuffer );
        desc32->CommandBufferSize = desc.CommandBufferSize;
        desc32->pAllocationList = PtrToUlong( desc.pAllocationList );
        desc32->AllocationListSize = desc.AllocationListSize;
        desc32->pPatchLocationList = PtrToUlong( desc.pPatchLocationList );
        desc32->PatchLocationListSize = desc.PatchLocationListSize;
    }
    return status;
}

NTSTATUS WINAPI wow64_NtGdiDdDDIOpenAdapterFromDeviceName( UINT *args )
{
    struct
    {
        ULONG pDeviceName;
        D3DKMT_HANDLE hAdapter;
        LUID AdapterLuid;
    } *desc32 = get_ptr( &args );

    D3DKMT_OPENADAPTERFROMDEVICENAME desc = { UlongToPtr( desc32->pDeviceName ) };
    NTSTATUS status;

    if (!(status = NtGdiDdDDIOpenAdapterFromDeviceName( &desc )))
    {
        desc32->hAdapter = desc.hAdapter;
        desc32->AdapterLuid = desc.AdapterLuid;
    }
    return status;
}

NTSTATUS WINAPI wow64_NtGdiDdDDIOpenAdapterFromHdc( UINT *args )
{
    struct
    {
        ULONG hDc;
        D3DKMT_HANDLE hAdapter;
        LUID AdapterLuid;
        D3DDDI_VIDEO_PRESENT_SOURCE_ID VidPnSourceId;
    } *desc32 = get_ptr( &args );

    D3DKMT_OPENADAPTERFROMHDC desc = { UlongToHandle( desc32->hDc ) };
    NTSTATUS status;

    if (!(status = NtGdiDdDDIOpenAdapterFromHdc( &desc )))
    {
        desc32->hAdapter = desc.hAdapter;
        desc32->AdapterLuid = desc.AdapterLuid;
        desc32->VidPnSourceId = desc.VidPnSourceId;
    }
    return status;
}

NTSTATUS WINAPI wow64_NtGdiDdDDIOpenAdapterFromLuid( UINT *args )
{
    D3DKMT_OPENADAPTERFROMLUID *desc = get_ptr( &args );

    return NtGdiDdDDIOpenAdapterFromLuid( desc );
}

NTSTATUS WINAPI wow64_NtGdiDdDDIQueryStatistics( UINT *args )
{
    D3DKMT_QUERYSTATISTICS *stats = get_ptr( &args );

    return NtGdiDdDDIQueryStatistics( stats );
}

NTSTATUS WINAPI wow64_NtGdiDdDDISetQueuedLimit( UINT *args )
{
    D3DKMT_SETQUEUEDLIMIT *desc = get_ptr( &args );

    return NtGdiDdDDISetQueuedLimit( desc );
}