/*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 and send them to the printer

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


#define INCL_32
#define INCL_VMANDDI
#include <ddi.h>

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

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


#define INCL_GENPLIB_JOURNAL
#define INCL_GENPLIB_MEMORY
#include <genplib.h>


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



// --------------------------------------------------------------------------------------------------------------------


BOOL DRVENTRY NewFrame( PDDC pddc )
{
  APIRET               rc;
  BOOL                 fOK;
  RECTL                rectl;
  REGREC               regrec;
  LONG                 lrc;
  ULONG                ulException;
  ULONG                ulFlags;



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


  pddc->cBand = 0;

  if( pddc->fMustJournal )
  {
    assert( pddc->hJournal );

    // Play the journal. Before it returns, it will have called
    // SendMonoBits(), (or some other page-rendering function)
    // as many times as there are bands to render. GENPLIB
    // journaling code will erase the PS before it plays the journal.

    ulFlags = PLAY_JOURNAL_BAND | PLAY_DESTRUCTIVE | PLAY_TOP_TO_BOTTOM;
    rc = GplJournalPlayInstance( pddc->hJournal, ulFlags );
    assert( rc );

    // begin recording the next page
    fOK = GplJournalCreateInstance( pddc->hJournal, NULL, 0 );
    assert( fOK );
  }
  else
  {
    // Call the same function that the journaling code would have called, had I been journaling.
    rectl.xLeft     = 0;
    rectl.yBottom   = 0;
    rectl.xRight    = pddc->JournalInput.usXLength -1;
    rectl.yTop      = pddc->JournalInput.usYLength -1;
    pddc->JournalInput.pfunBandCallback( pddc, &rectl );

    // Clear the image from the surface bitmap.
    fOK = GreErasePS( pddc->hdc );
    assert( fOK );
  }



  if( !pddc->fInitPage )
  {
    // fInitPage is off. Only WriteOutput() turns it off.
    // Conclusion: something was written on this page.

    // DEVICE_SPECIFIC: eject this page
    prtputs( pddc, "\014" );
  }


  // Defer page initialization until we know there is a next page.
  // InitPage() is called from WriteOutput().
  pddc->fInitPage = TRUE;


  lrc = TRUE;

depart:
  UNREGISTERHANDLER( regrec );
  return lrc;
}





// --------------------------------------------------------------------------------------------------------------------
// DEVICE_SPECIFIC: send mono bitmap bits to printer. This entire function
// is specific to the driven device.

LONG APIENTRY SendMonoBits( PDDC pddc, PRECTL prectl )
{
  BOOL     fWhite;
  LONG     cbScanline;
  LONG     cb;
  LONG     xPels;
  LONG     yPels;
  LONG     yTopMarginOffset;
  PCHAR    pchSrc;
  PCHAR    pch;
  LONG     i;
  LONG     k;


  // Expecting monochrome.
  assert( 1 ==  pddc->pDeviceSurface->SurfaceBmapInfo.ulBpp );

  assert( pddc );
  if( pddc->fAbortDocCalled ) {
    return 1;
  }

  assert( pddc->pDeviceSurface );
  assert( pddc->pDeviceSurface->SurfaceBmapInfo.pBits );
  if( !pddc->pDeviceSurface->SurfaceBmapInfo.pBits ) {
    // must have bits.
    return 1;
  }

  if( pddc->fRawDataEscape ) {
    // We received raw-data escapes. Don't send raster
    // because application is mixing standard printing and
    // raw data.
    return 1;
  }


  /*

  Consider the scenario where an application does a
  DevEscape(DEVESC_NEWFRAME) followed by a DevEscape(DEVESC_ENDDOC) with no
  intervening drawing. The driver must detect this and not eject an extra
  blank page at the end of the job.

  For each of DEVESC_NEWFRAME and DEVESC_ENDDOC, the driver has to call
  NewFrame(). NewFrame() must have a mechanism to detect this scenario.

  To address this scenario, code SendMonoBits() and other surface-rendering
  functions so that they generate no output whatsoever if there has been no
  drawing on the surface. By generating no output, the fInitPage flag
  remains on. After rendering the page, NewFrame() may check the fInitPage
  flag. If off, there was drawing, and a page eject is necessary. If on,
  there was no output, and a page eject is unnecessary.

  */


  if( pddc->fEndDocCalled )
  {
    // Scan for any "on" bits which indicate drawing occurred.
    fWhite = TRUE;
    cb = pddc->pDeviceSurface->SurfaceBmapInfo.ulHeight * pddc->pDeviceSurface->SurfaceBmapInfo.ulBytesPerLine;
    for( pch = pddc->pDeviceSurface->SurfaceBmapInfo.pBits; cb; cb-- )
    {
      if( *pch++ )
      {
        fWhite = FALSE;
        break;
      }
    }
    if( fWhite )
    {
      return 1;
    }
  }




  DBPRINTF(( "Band %d\n", pddc->cBand ));
  pddc->cBand++;

  DBPRINTF(( "SendBits rectangle: xLeft=%d; yBottom=%d; xRight=%d; yTop=%d\n", prectl->xLeft, prectl->yBottom, prectl->xRight, prectl->yTop ));

  // size of band rectangle
  xPels = 1 + prectl->xRight - prectl->xLeft;
  yPels = 1 + prectl->yTop   - prectl->yBottom;

  DBPRINTF(( "SendBits rectangle in pels: xPels=%d; yPels=%d\n", xPels, yPels ));

  assert( 0 < xPels && xPels <= max( pddc->pFormInfo->hcinfo.yPels, pddc->pFormInfo->hcinfo.xPels ));
  assert( 0 < yPels && yPels <= max( pddc->pFormInfo->hcinfo.yPels, pddc->pFormInfo->hcinfo.xPels ));
  assert( yPels <= pddc->pDeviceSurface->SurfaceBmapInfo.ulHeight );


  // set x,y position (x is assumed to be zero)
  assert( 0 == prectl->xLeft );
  yTopMarginOffset = pddc->pSupportedDevice->ulYResolution / 5;
  prtprintf( pddc, "\033*p0x%dY",   yTopMarginOffset + pddc->JournalInput.usYLength - ( prectl->yTop + 1 )   );

  // set raster width
  prtprintf( pddc, "\033*r%dS", xPels );

  // start raster
  prtputs( pddc, "\033*r1A" );

  pchSrc      = pddc->pDeviceSurface->SurfaceBmapInfo.pBits;
  cbScanline  = pddc->pDeviceSurface->SurfaceBmapInfo.ulBytesPerLine;

  for( i=0; i < yPels; i++ ) {

    // needs work. compress raster data, then send it

    // detect an all-white scan line
    fWhite = TRUE;
    for( k = 0, pch = pchSrc; k < cbScanline; k++, pch++ ) {
      if( *pch ) {
        fWhite = FALSE;
        break;
      }
    }

    if( fWhite ) {
      prtputs( pddc, "\033*b0m0W" );
    } else {
      prtprintf( pddc, "\033*b0m%dW", cbScanline  );
      prtput( pddc, pchSrc, cbScanline  );
    }
    pchSrc += cbScanline;
  }

  // end raster
  prtputs( pddc, "\033*rC" );

  return 1;
}



