/*
 * GDI bit-blit operations
 *
 * Copyright 1993, 1994  Alexandre Julliard
 */

#include <string.h>

#include "gdi.h"
#include "metafiledrv.h"
#include "heap.h"
#include "debugtools.h"
#include "bitmap.h"

DEFAULT_DEBUG_CHANNEL(metafile);

/***********************************************************************
 *           MFDRV_PatBlt
 */
BOOL MFDRV_PatBlt( DC *dc, INT left, INT top,
                     INT width, INT height, DWORD rop )
{
    MFDRV_MetaParam6( dc, META_PATBLT, left, top, width, height,
		      HIWORD(rop), LOWORD(rop) );
    return TRUE;
}


/***********************************************************************
 *           MFDRV_BitBlt
 */
BOOL MFDRV_BitBlt( DC *dcDst, INT xDst, INT yDst, INT width, INT height,
		   DC *dcSrc, INT xSrc, INT ySrc, DWORD rop )
{
    BOOL ret;
    DWORD len;
    METARECORD *mr;
    BITMAP16  BM;

    GetObject16(dcSrc->hBitmap, sizeof(BITMAP16), &BM);
    len = sizeof(METARECORD) + 12 * sizeof(INT16) + BM.bmWidthBytes * BM.bmHeight;
    if (!(mr = HeapAlloc(GetProcessHeap(), 0, len)))
	return FALSE;
    mr->rdFunction = META_BITBLT;
    *(mr->rdParm + 7) = BM.bmWidth;
    *(mr->rdParm + 8) = BM.bmHeight;
    *(mr->rdParm + 9) = BM.bmWidthBytes;
    *(mr->rdParm +10) = BM.bmPlanes;
    *(mr->rdParm +11) = BM.bmBitsPixel;
    TRACE("len = %ld  rop=%lx  \n",len,rop);
    if (GetBitmapBits(dcSrc->hBitmap,BM.bmWidthBytes * BM.bmHeight,
                        mr->rdParm +12))
    {
      mr->rdSize = len / sizeof(INT16);
      *(mr->rdParm) = HIWORD(rop);
      *(mr->rdParm + 1) = ySrc;
      *(mr->rdParm + 2) = xSrc;
      *(mr->rdParm + 3) = height;
      *(mr->rdParm + 4) = width;
      *(mr->rdParm + 5) = yDst;
      *(mr->rdParm + 6) = xDst;
      ret = MFDRV_WriteRecord( dcDst, mr, mr->rdSize * 2);
    } 
    else
        ret = FALSE;
    HeapFree( GetProcessHeap(), 0, mr);
    return ret;
}



/***********************************************************************
 *           MFDRV_StretchBlt
 * this function contains TWO ways for procesing StretchBlt in metafiles,
 * decide between rdFunction values  META_STRETCHBLT or META_DIBSTRETCHBLT
 * via #define STRETCH_VIA_DIB
 */
#define STRETCH_VIA_DIB
#undef  STRETCH_VIA_DIB

BOOL MFDRV_StretchBlt( DC *dcDst, INT xDst, INT yDst, INT widthDst,
		       INT heightDst, DC *dcSrc, INT xSrc, INT ySrc,
		       INT widthSrc, INT heightSrc, DWORD rop )
{
    BOOL ret;
    DWORD len;
    METARECORD *mr;
    BITMAP16  BM;
#ifdef STRETCH_VIA_DIB    
    LPBITMAPINFOHEADER lpBMI;
    WORD nBPP;
#endif  
    GetObject16(dcSrc->hBitmap, sizeof(BITMAP16), &BM);
#ifdef STRETCH_VIA_DIB
    nBPP = BM.bmPlanes * BM.bmBitsPixel;
    len = sizeof(METARECORD) + 10 * sizeof(INT16) 
            + sizeof(BITMAPINFOHEADER) + (nBPP != 24 ? 1 << nBPP: 0) * sizeof(RGBQUAD) 
              + ((BM.bmWidth * nBPP + 31) / 32) * 4 * BM.bmHeight;
    if (!(mr = HeapAlloc( GetProcessHeap(), 0, len)))
	return FALSE;
    mr->rdFunction = META_DIBSTRETCHBLT;
    lpBMI=(LPBITMAPINFOHEADER)(mr->rdParm+10);
    lpBMI->biSize      = sizeof(BITMAPINFOHEADER);
    lpBMI->biWidth     = BM.bmWidth;
    lpBMI->biHeight    = BM.bmHeight;
    lpBMI->biPlanes    = 1;
    lpBMI->biBitCount  = nBPP;                              /* 1,4,8 or 24 */
    lpBMI->biClrUsed   = nBPP != 24 ? 1 << nBPP : 0;
    lpBMI->biSizeImage = ((lpBMI->biWidth * nBPP + 31) / 32) * 4 * lpBMI->biHeight;
    lpBMI->biCompression = BI_RGB;
    lpBMI->biXPelsPerMeter = MulDiv(GetDeviceCaps(dcSrc->hSelf,LOGPIXELSX),3937,100);
    lpBMI->biYPelsPerMeter = MulDiv(GetDeviceCaps(dcSrc->hSelf,LOGPIXELSY),3937,100);
    lpBMI->biClrImportant  = 0;                          /* 1 meter  = 39.37 inch */

    TRACE("MF_StretchBltViaDIB->len = %ld  rop=%lx  PixYPM=%ld Caps=%d\n",
               len,rop,lpBMI->biYPelsPerMeter,GetDeviceCaps(hdcSrc,LOGPIXELSY));
    if (GetDIBits(hdcSrc,dcSrc->w.hBitmap,0,(UINT)lpBMI->biHeight,
                  (LPSTR)lpBMI + DIB_BitmapInfoSize( (BITMAPINFO *)lpBMI,
                                                     DIB_RGB_COLORS ),
                  (LPBITMAPINFO)lpBMI, DIB_RGB_COLORS))
#else
    len = sizeof(METARECORD) + 15 * sizeof(INT16) + BM.bmWidthBytes * BM.bmHeight;
    if (!(mr = HeapAlloc( GetProcessHeap(), 0, len )))
	return FALSE;
    mr->rdFunction = META_STRETCHBLT;
    *(mr->rdParm +10) = BM.bmWidth;
    *(mr->rdParm +11) = BM.bmHeight;
    *(mr->rdParm +12) = BM.bmWidthBytes;
    *(mr->rdParm +13) = BM.bmPlanes;
    *(mr->rdParm +14) = BM.bmBitsPixel;
    TRACE("len = %ld  rop=%lx  \n",len,rop);
    if (GetBitmapBits( dcSrc->hBitmap, BM.bmWidthBytes * BM.bmHeight,
                         mr->rdParm +15))
#endif    
    {
      mr->rdSize = len / sizeof(INT16);
      *(mr->rdParm) = LOWORD(rop);
      *(mr->rdParm + 1) = HIWORD(rop);
      *(mr->rdParm + 2) = heightSrc;
      *(mr->rdParm + 3) = widthSrc;
      *(mr->rdParm + 4) = ySrc;
      *(mr->rdParm + 5) = xSrc;
      *(mr->rdParm + 6) = heightDst;
      *(mr->rdParm + 7) = widthDst;
      *(mr->rdParm + 8) = yDst;
      *(mr->rdParm + 9) = xDst;
      ret = MFDRV_WriteRecord( dcDst, mr, mr->rdSize * 2);
    }  
    else
        ret = FALSE;
    HeapFree( GetProcessHeap(), 0, mr);
    return ret;
}


/***********************************************************************
 *           MFDRV_StretchDIBits
 */
INT MFDRV_StretchDIBits( DC *dc, INT xDst, INT yDst, INT widthDst,
			 INT heightDst, INT xSrc, INT ySrc, INT widthSrc,
			 INT heightSrc, const void *bits,
			 const BITMAPINFO *info, UINT wUsage, DWORD dwRop )
{
    DWORD len, infosize, imagesize;
    METARECORD *mr;

    infosize = DIB_BitmapInfoSize(info, wUsage);
    imagesize = DIB_GetDIBImageBytes( info->bmiHeader.biWidth,
				      info->bmiHeader.biHeight,
				      info->bmiHeader.biBitCount );

    len = sizeof(METARECORD) + 10 * sizeof(WORD) + infosize + imagesize;
    mr = (METARECORD *)HeapAlloc( GetProcessHeap(), 0, len );
    if(!mr) return 0;

    mr->rdSize = len / 2;
    mr->rdFunction = META_STRETCHDIB;
    mr->rdParm[0] = LOWORD(dwRop);
    mr->rdParm[1] = HIWORD(dwRop);
    mr->rdParm[2] = wUsage;
    mr->rdParm[3] = (INT16)heightSrc;
    mr->rdParm[4] = (INT16)widthSrc;
    mr->rdParm[5] = (INT16)ySrc;
    mr->rdParm[6] = (INT16)xSrc;
    mr->rdParm[7] = (INT16)heightDst;
    mr->rdParm[8] = (INT16)widthDst;
    mr->rdParm[9] = (INT16)yDst;
    mr->rdParm[10] = (INT16)xDst;
    memcpy(mr->rdParm + 11, info, infosize);
    memcpy(mr->rdParm + 11 + infosize / 2, bits, imagesize);
    MFDRV_WriteRecord( dc, mr, mr->rdSize * 2 );
    HeapFree( GetProcessHeap(), 0, mr );
    return heightSrc;
}

	
/***********************************************************************
 *           MFDRV_SetDIBitsToDeivce
 */
INT MFDRV_SetDIBitsToDevice( DC *dc, INT xDst, INT yDst, DWORD cx,
			     DWORD cy, INT xSrc, INT ySrc, UINT startscan,
			     UINT lines, LPCVOID bits, const BITMAPINFO *info,
			     UINT coloruse )

{
    DWORD len, infosize, imagesize;
    METARECORD *mr;

    infosize = DIB_BitmapInfoSize(info, coloruse);
    imagesize = DIB_GetDIBImageBytes( info->bmiHeader.biWidth,
				      info->bmiHeader.biHeight,
				      info->bmiHeader.biBitCount );

    len = sizeof(METARECORD) + 8 * sizeof(WORD) + infosize + imagesize;
    mr = (METARECORD *)HeapAlloc( GetProcessHeap(), 0, len );
    if(!mr) return 0;

    mr->rdSize = len / 2;
    mr->rdFunction = META_SETDIBTODEV;
    mr->rdParm[0] = coloruse;
    mr->rdParm[1] = lines;
    mr->rdParm[2] = startscan;
    mr->rdParm[3] = (INT16)ySrc;
    mr->rdParm[4] = (INT16)xSrc;
    mr->rdParm[5] = (INT16)cy;
    mr->rdParm[6] = (INT16)cx;
    mr->rdParm[7] = (INT16)yDst;
    mr->rdParm[8] = (INT16)xDst;
    memcpy(mr->rdParm + 9, info, infosize);
    memcpy(mr->rdParm + 9 + infosize / 2, bits, imagesize);
    MFDRV_WriteRecord( dc, mr, mr->rdSize * 2 );
    HeapFree( GetProcessHeap(), 0, mr );
    return lines;
}