/*DDK*************************************************************************/
/*                                                                           */
/* COPYRIGHT    Copyright (C) 1995 IBM Corporation                           */
/*                                                                           */
/*    The following IBM OS/2 WARP source code is provided to you solely for  */
/*    the purpose of assisting you in your development of OS/2 WARP device   */
/*    drivers. You may use this code in accordance with the IBM License      */
/*    Agreement provided in the IBM Device Driver Source Kit for OS/2. This  */
/*    Copyright statement may not be removed.                                */
/*                                                                           */
/*****************************************************************************/
// newframe.c
// get bits from shadow DC and send them to the printer

#define INCL_DOS
#define INCL_SPL
#define INCL_SPLFSE
#define INCL_PM
#include <os2.h>

#define INCL_GRE_DEVMISC2
#define INCL_GRE_DEVICE
#define INCL_GRE_BITMAPS
#define INCL_GRE_DEVSUPPORT
#define INCL_DDIMISC
#include <pmddi.h>

// c includes
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <setjmp.h>
#include <builtin.h>

#include "def.h"
#include "driver.h"
#include "funcs.h"
#include "assert.h"



#define LEN_BITBUFFER     0x040000


// --------------------------------------------------------------------------------------------------------------------
// has the side effect of erasing the shadow DC after fetching the bits


BOOL NewFrame( PDDC pddc )
{
  APIRET               rc;
  BITMAPINFOHEADER     bmi;
  register USHORT      fBitsOn = FALSE;
  LONG                 cBytesPerScanLine;
  LONG                 cColors;
  LONG                 cLines;
  LONG                 cLinesPerBuffer;
  LONG                 cLinesScanned;
  LONG                 lrc;
  LONG                 y;
  LONG                 i;
  PBITMAPINFO          pbmi = NULL;
  PCHAR                pchBitBuffer = NULL;
  register PCHAR       pch;
  REGREC               regrec;
  ULONG                ulException;




  REGISTERHANDLER( regrec );
  ulException = setjmp( regrec.jmp );
  if( ulException ) {
    assert( FALSE );
    CheckForTermination( &regrec, ulException, pddc );
    // error result
    lrc = FALSE;
    goto depart;
  }


  // DEVICE_SPECIFIC: Getting the bitmap bits depends on the kind of bitmap created in ENABLE.C.
  // DEVICE_SPECIFIC: May need to reset the printer if printer not already reset.



  // get information about the bitmap in the shadow DC
  lrc = GreGetBitmapParameters( pddc->hbmShadow, &bmi );
  assert( lrc );

  // compute the number of bytes per line; must be the next greater or equal multiple of four
  cBytesPerScanLine = (( (bmi.cBitCount * bmi.cx) +31 ) >> 5) << 2;

  // compute the number of scan lines that can fit into one bitbuffer
  cLinesPerBuffer = LEN_BITBUFFER / cBytesPerScanLine;

  // DEVICE_SPECIFIC: 2 color (monochrome)
  cColors = 2;

  // use DosAllocMem directly for large allocations such as this
  rc = DosAllocMem( (PPVOID) &pchBitBuffer, cBytesPerScanLine*cLinesPerBuffer, PAG_WRITE | PAG_COMMIT );
  assert( rc == 0 );

  // use regular heap alloc for bitmapinfo
  pbmi = (PBITMAPINFO) AllocMem( pddc->pdb->pvHeap, sizeof(BITMAPINFO) + cColors * sizeof( RGB )  );
  assert( pbmi );

  pbmi->cbFix     = sizeof( BITMAPINFOHEADER );
  pbmi->cPlanes   = bmi.cPlanes;
  pbmi->cBitCount = bmi.cBitCount;




#ifndef NDEBUG
  // this is debugging code: show the shadow DC bitmap on the screen
  {
    HPS                  hps;
    POINTL               aptl[ 4 ];
    RECTL                rectl;

    // blt to the screen
    hps = WinGetScreenPS( HWND_DESKTOP );
    assert( hps );

    // get size of screen
    WinQueryWindowRect( HWND_DESKTOP, &rectl );

    // flood screen with black
    WinFillRect( hps, &rectl, CLR_BLACK );

    // 1:1 blt: blt lower left part of shadow DC bitmap; this will be fast, but can't see it all on screen
    // target points
    aptl[ 0 ].x = 0;
    aptl[ 0 ].y = 0;
    aptl[ 1 ].x = rectl.xRight - 1;
    aptl[ 1 ].y = rectl.yTop - 1;
    // source points
    aptl[ 2 ].x = 0;
    aptl[ 2 ].y = 0;
    aptl[ 3 ].x = rectl.xRight;
    aptl[ 3 ].y = rectl.yTop;

    // have to de-select bitmap prior to wcbitblt
    pddc->hbmShadow = GreSelectBitmap( pddc->hdcShadow, 0 );
    assert( pddc->hbmShadow  != HBM_ERROR );

    // invert the bits on the blt: NOTSRC
    lrc = GpiWCBitBlt( hps, pddc->hbmShadow, 4, aptl, ROP_NOTSRCCOPY, BBO_OR );
    assert( lrc != GPI_ERROR );

    // stop on an int 3 at debug terminal
    DBPRINTF(( "Done with 1:1 bitblt. Enter G to go.\n" ));
    _interrupt(3);
    DBPRINTF(( "Now doing stretch blt. Please wait.\n" ));

    // flood screen with black
    WinFillRect( hps, &rectl, CLR_BLACK );

    // stretch blt -- can be slow
    // preserve aspect ratio of shadow bitmap, provided display has square pixels like VGA
    // target points
    aptl[ 0 ].x = 0;
    aptl[ 0 ].y = 0;
    aptl[ 1 ].x = ( pddc->pdb->pFormInfo->hcinfo.xPels * rectl.yTop ) / pddc->pdb->pFormInfo->hcinfo.yPels;
    aptl[ 1 ].y = rectl.yTop - 1;
    // source points
    aptl[ 2 ].x = 0;
    aptl[ 2 ].y = 0;
    aptl[ 3 ].x = pddc->pdb->pFormInfo->hcinfo.xPels;
    aptl[ 3 ].y = pddc->pdb->pFormInfo->hcinfo.yPels;

    // already de-selected bitmap above

    // invert the bits on the blt: NOTSRC
    lrc = GpiWCBitBlt( hps, pddc->hbmShadow, 4, aptl, ROP_NOTSRCCOPY, BBO_AND );
    assert( lrc != GPI_ERROR );

    // stop on an int 3 at debug terminal
    DBPRINTF(( "Done with stretch bitblt. Enter G to go.\n" ));
    _interrupt(3);

    // select bitmap back into shadow DC
    lrc = GreSelectBitmap( pddc->hdcShadow, pddc->hbmShadow );
    assert( lrc == 0 );

    // force a re-paint on the display
    WinInvalidateRect( HWND_DESKTOP, NULL, TRUE );

    // return ps to cache
    lrc = (LONG) WinReleasePS( hps );
    assert( lrc );
  }

#endif





  for( y = 0; y < bmi.cy; y+=cLinesPerBuffer ) {

    // this is how many scan lines to get
    cLines = min( cLinesPerBuffer, bmi.cy  - y );

    // get the bitmap bits from the shadow DC bitmap
    cLinesScanned = GreGetBitmapBits( pddc->hdcShadow, 0, y, cLines, pchBitBuffer, pbmi );
    assert( cLinesScanned == cLines );

    // bits from shadow DC are inverted: bit=1 ==>white;  bit=0 ==>black
    // invert the bits here
    for( i = cLinesScanned*cBytesPerScanLine, pch = pchBitBuffer; i ; i--, pch++ ) {
      // xor the byte of bits with FFh
      *pch ^= 0xFF;
      // determine if there are any "on" bits at all
      fBitsOn |= *pch;
    }

    // DEVICE_SPECIFIC: put device-specific escape codes around the bits in pchBitBuffer
    // DEVICE_SPECIFIC: to prepare it as raster data for a capable printer


    // if OD_DIRECT,  send the raster escapes using PrtWrite( pddc->pdb->hspl, ... );
    // if OD_QUEUED and PM_Q_RAW,  send escapes using SplQmWrite( pddc->pdb->hspl, ... );

  }


  if( fBitsOn ) {
    // DEVICE_SPECIFIC: reference pddc->pdb->cCopies for multiple, uncollated copies of this page
    // DEVICE_SPECIFIC: need code to send the printer-specific escape code to eject the page

    // bump page count
    pddc->pdb->ulPage++;
  }

  // erase the shadow DC bitmap
  lrc = GreErasePS( pddc->hdcShadow );
  assert( lrc );

  lrc = TRUE;



depart:

  // clean up allocations if allocated

  if( pbmi ) {
    FreeMem( pbmi );
    pbmi = NULL;
  }

  if( pchBitBuffer ) {
    rc = DosFreeMem( pchBitBuffer );
    assert( rc == 0 );
    pchBitBuffer = NULL;
  }


  UNREGISTERHANDLER( regrec );
  return lrc;

}

