/*DDK*************************************************************************/
/*                                                                           */
/* COPYRIGHT (C) Lexmark Corporation, 1989                                   */
/* 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.                                */
/*                                                                           */
/*****************************************************************************/
/**************************************************************************
 *
 * SOURCE FILE NAME = PRDJSUBR
 *
 * DESCRIPTIVE NAME =
 *
 *
 * VERSION
 *
 * DATE
 *
 * DESCRIPTION
 *
 * FUNCTIONS   prdj_MakeBand
 *             prdj_FreeBand
 *             prdj_UpdateBandCoordinates
 *             prdj_LastBand
 *
 * ENTRY POINTS:
 *
 * DEPENDENCIES:
 *
 * NOTES
 *
 *
 * STRUCTURES
 *
 * EXTERNAL REFERENCES
 *
 * EXTERNAL FUNCTIONS
 *
*/

#define INCL_32                         /* Convert to C/SET2    CON3201       */
#define INCL_DOSPROCESS                 /* Convert to C/SET2    CON3201       */
#define INCL_DOSSEMAPHORES
#define INCL_GREALL
#define INCL_GPIPRIMITIVES
#define INCL_WINHEAP
#define INCL_GPIBITMAPS
#include <os2.h>
#undef INCL_DOSPROCESS                  /* Convert to C/SET2    CON3201       */
#undef INCL_DOSSEMAPHORES
#undef INCL_GREALL
#undef INCL_GPIPRIMITIVES
#undef INCL_WINHEAP
#undef INCL_GPIBITMAPS

#define INCL_DDIBUNDLES
#define INCL_DDIFONTSTRUCS
#define INCL_DDIDEFS
#define INCL_DDIMISC
#include <pmddi.h>
#undef INCL_DDIBUNDLES
#undef INCL_DDIFONTSTRUCS
#undef INCL_DDIDEFS
#undef INCL_DDIMISC

#define INCL_WINP_SELECTIVE
#define INCL_WINP_SEI
#include <pmwinx.h>
#undef INCL_WINP_SELECTIVE
#undef INCL_WINP_SEI
#undef INCL_32                          /* Convert to C/SET2    CON3201       */

#define NO_CONSTANT_INCL
#include <prdinclt.h>
#undef NO_CONSTANT_INCL

#include <prdjextf.h>
#include <prdbtyp1.h>
#include <prdbextf.h>
#include <prdgextf.h>
#include <prdyextf.h>

#include <prdbsize.h>
#include <prdncone.h>
#include <prdconse.h>

extern GDTType   GDT;
extern USHORT    debug_nobands;

/**********************************************************************/
/*                                                                    */
/*   FUNCTION: prdj_MakeBand                                          */
/*                                                                    */
/*   PARAMETERS:                                                      */
/*                                                                    */
/*   lpDCI       DCIData;  Pointer to DC Instance data                */
/*   lpBand      hBand;    Pointer to band data to be set             */
/*                                                                    */
/*   DESCRIPTION:                                                     */
/*                                                                    */
/*   This function makes a band based on the size of a page and the   */
/*   number of bands per page.  From the dimensions it calculates     */
/*   for the band it creates a bitmap for it and adds it to the       */
/*   bitmap list and selects it in the DC Instance data.  It then     */
/*   sets the band data at hBand to give the position of the band on  */
/*   the page and adds this information to the bitmaps entry in the   */
/*   bitmap list and sets the current text band to null.              */
/*                                                                    */
/*   BAND1 : This function simplified.                                */
/**********************************************************************/
#if 0
USHORT  pascal prdj_MakeBand ( DCIData,
                               hBand )

lpDCI       DCIData;
lpBand      hBand;
#endif

SHORT prdj_MakeBand ( lpDCI  DCIData,                      /* CON3201 */
                      lpBand hBand )                       /* CON3201 */

{
/**********************************************************************/
/* PD00253 : Banding is always true. Remove this constant from DDCONE */
/**********************************************************************/
#define DDT_BANDING

    /******************************************************************/
    /* Local Variables                                                */
    /******************************************************************/
    lpDDTType     pDDT;                /* Pointer to DDT in PDB       */
    BitmapParms   BitmapParms;         /* Defines bitmap              */
    USHORT        Depth;               /* Depth of page/band in pels  */
    USHORT        Width;               /* Width of page/band in pels  */
    USHORT        BandDepth;
    USHORT        NoOfBands;
    ULONG         TotalBytes;          /* Band size in bytes          */
    pBMListEntry  ListEntry;           /* Bitmap list entry           */

    /******************************************************************/
    /* Get some useful pointers.                                      */
    /******************************************************************/
    pDDT  = &(DCIData->DCIPdbInstance->DDT);

    /******************************************************************/
    /* For a QUEUED-STD or an INFO DC the driver does no drawing so   */
    /* just get a dummy band.                                         */
    /******************************************************************/
    if ( DCIData->Flags & (QUEUED_STD | INFO) )
    {
        /**************************************************************/
        /* For INFO and QUEUED STD DC's create a dummy list entry.    */
        /* Although we don't do any drawing for these we still        */
        /* allocate a list entry so that any checks in drawing        */
        /* routines will work.                                        */
        /**************************************************************/
        if ( prdg_AllocGlobalHeapItem( LIST_ENTRY_SIZE,
                                    /* (PBYTE far *)&ListEntry) != OK ) */
                                       (PBYTE *)&ListEntry) != OK ) /*CON3201*/
            return (ERROR_NEG);

        /**************************************************************/
        /* Set the list entry values.                                 */
        /**************************************************************/
        ListEntry->DCHandle = 0;
        ListEntry->Bitmap   = FNULL;
        ListEntry->Huge     = 0;

        ListEntry->Parms.Width  = 8;
        ListEntry->Parms.Height = 8;
        ListEntry->Parms.Planes = 1;

        ListEntry->Parms.Bitcount    = pDDT->DDTFormat->BitCount;
        ListEntry->Parms.BytesPerRow = pDDT->DDTFormat->BitCount;

        if ( ListEntry->Parms.Bitcount == 1 )
            ListEntry->DCTPtr = GDT.GDT11ColorTable;
        else if ( ListEntry->Parms.Bitcount == 4 )
            ListEntry->DCTPtr = GDT.GDT41ColorTable;
        else if ( ListEntry->Parms.Bitcount == 8 )
            ListEntry->DCTPtr = GDT.GDT81ColorTable;

        ListEntry->BandXOrigin = ListEntry->BandYOrigin = 0;
        ListEntry->XOrigin     = ListEntry->YOrigin     = 0;
        ListEntry->BMLocked    = 0;

        /**************************************************************/
        /* Select it into the DC and return.                          */
        /**************************************************************/
        DCIData->DCISelBitmap = (PBYTE)ListEntry;
        return (OK);
    }

    /******************************************************************/
    /* For QUEUED-RAW and DIRECT DCs allocate enough memory for the   */
    /* full page, or as much as we can.                               */
    /******************************************************************/
    Width = DCIData->DCIPdbInstance->PageWidthPels;
    Depth = DCIData->DCIPdbInstance->PageDepthPels;

    /******************************************************************/
    /* Calculate the depth of the band to make.  First determine the  */
    /* amount of paper left on the current form in the printer.       */
    /* DCIBandLowY is the position of the last line on the page which */
    /* has been printed.  In PORTRAIT  mode this is counted from the  */
    /* bottom of the page upwards, in LANSCAPE mode it is counted from*/
    /* the top of the page down:                                      */
    /*                                                                */
    /*   PORTRAIT                      LANDSCAPE                      */
    /*                                                                */
    /*                                 < Direction of paper feed <    */
    /*  o             o               o o o o o o o o o o o o o       */
    /*  o Printed     o                      |       |       |        */
    /*  o_____________o                Prin- | Prin- |       |        */
    /*  o             o                -ted  | -ted  |       |        */
    /*  o Printed     o                      |       |       |        */
    /*  o_____________o                      |       |       |        */
    /*  o             o ^  BandLowY   o o o o o o o o o o o o o       */
    /*  o             o ^             >>>>>>>>>>>>>>>>                */
    /*  o_____________o ^                  BandLowY                   */
    /*                                                                */
    /* So, in PORTRAIT mode the amount of paper left will simply be   */
    /* DCIBandLowY and in LANDSCAPE mode it will the total length of  */
    /* a sheet of paper (Depth) minus DCIBandLowY.                    */
    /******************************************************************/
    if ( DCIData->DCIPdbInstance->Orientation == PORTRAIT )
    {
        Depth = DCIData->DCIBandLowY;
    }
    else
    {
        Depth = Depth - DCIData->DCIBandLowY;
    }

    BitmapParms.Planes   = pDDT->DDTFormat->Planes;
    BitmapParms.Bitcount = pDDT->DDTFormat->BitCount;

#ifdef DEBUG_BANDING
    /******************************************************************/
    /* Debug processing. When this function is called from Prepare-   */
    /* NextPage change debug_nobands to the number of bands required. */
    /* When it is called from SendInitAndPage just hit go.            */
    /*                                                                */
    /* To test banding we force the code to create more than one band */
    /* Each time round the number of bands is decremented giving      */
    /* equal size bands. To get larger bands                          */
    /******************************************************************/
    if (debug_nobands > 1) { debug_nobands--; }
    haltproc();
    NoOfBands = debug_nobands;
#else
    /******************************************************************/
    /* BAND2 : Start off with one band.                               */
    /******************************************************************/
    NoOfBands = 1;
#endif

    /******************************************************************/
    /* Now determine the size of band to make, based on the number of */
    /* BandsPerPage.  Note the add-in of (BandsPerPage-1) to prevent  */
    /* rounding errors so that all the lines on the page are printed. */
    /* BandsPerPage will always be 1 unless banding is allowed.       */
    /******************************************************************/
    do
    {
        /**************************************************************/
        /* Calculate the number of pel lines a single band is going   */
        /* to take up.                                                */
        /**************************************************************/
        BandDepth = (Depth + NoOfBands - 1) / NoOfBands;

        /**************************************************************/
        /* Set up the bitmap parameters, the width and height depend  */
        /* on whether we are in LANDSCAPE or PORTRAIT mode and the    */
        /* Planes and BitCount come from the DDT.                     */
        /**************************************************************/
        if ( DCIData->DCIPdbInstance->Orientation == PORTRAIT )
        {
            BitmapParms.Width  = Width;
            BitmapParms.Height = BandDepth;
        }
        else
        {
            BitmapParms.Width  = BandDepth;
            BitmapParms.Height = Width;
        }

        /**************************************************************/
        /* The second parameter being TRUE indicates that this is the */
        /* band being set up so that CreateBitmap knows that it needs */
        /* to initialise the bitmap to CLR_WHITE.                     */
        /**************************************************************/
        if ( (ListEntry = prdb_CreateBitmap( DCIData,
                                             TRUE,
                                             &BitmapParms )) )
        {
            TRACE4(TFUNC, "Got bitmap for band", FNULL, 0);
            Depth = BandDepth;
            break;
        }
        else
        {
            /**********************************************************/
            /* Failed to get the full amount of memory.               */
            /**********************************************************/
#ifndef DDT_BANDING
            /**********************************************************/
            /* If banding is not supported in this driver then        */
            /* reflect this error further up.                         */
            /**********************************************************/
            return (ERROR_NEG);
#else
            /**********************************************************/
            /* Failed to get memory, but we are banding so we should  */
            /* try again.  Except that we should be able to get one   */
            /* segment.  So if we have failed to get less than a      */
            /* segment return the error to the application            */
            /**********************************************************/
            TotalBytes = (ULONG)BitmapParms.Height *
                              ((((ULONG)BitmapParms.Width *
                                 (ULONG)BitmapParms.Bitcount + 31)/32) * 4);

            if (TotalBytes < 0x10000)
            {
                return (ERROR_NEG);
            }

            /**********************************************************/
            /* Now try with one extra band.  Ie divide the remaining  */
            /* page in half.                                          */
            /**********************************************************/
            NoOfBands++;
#endif
        }

    } while (TRUE);

    /******************************************************************/
    /* Set BandsPerPage to something other than one since this is     */
    /* used as a flag to stop and start the journal.  Check is to     */
    /* make sure we don't set it to back to one when banding is being */
    /* used and we're on the last band.                               */
    /******************************************************************/
    if ((SHORT)NoOfBands > 1)
    {
        pDDT->DDTBandsPerPage = NoOfBands;
    }

    /******************************************************************/
    /* Select the bitmap into the DC by setting the pointer in the    */
    /* DC Instance data.                                              */
    /******************************************************************/
    DCIData->DCISelBitmap = (PBYTE)ListEntry;

    /******************************************************************/
    /* Set the band coordinates according to the width and height of  */
    /* the acquired bitmap (allowing for DCIBandLowY which has not    */
    /* been updated yet). Set the band's graphics band to the bitmap  */
    /* and set the text band to NULL.                                 */
    /******************************************************************/
    if ( DCIData->DCIPdbInstance->Orientation == PORTRAIT )
    {
        hBand->BDCoords[0].X = 0;
        hBand->BDCoords[0].Y = DCIData->DCIBandLowY - Depth;
        hBand->BDCoords[1].X = Width;
        hBand->BDCoords[1].Y = DCIData->DCIBandLowY;
    }
    else
    {
        hBand->BDCoords[0].X = DCIData->DCIBandLowY;
        hBand->BDCoords[0].Y = 0;
        hBand->BDCoords[1].X = DCIData->DCIBandLowY + Depth;
        hBand->BDCoords[1].Y = Width;
    }

    /******************************************************************/
    /* Set the bitmap pointer.                                        */
    /******************************************************************/
    hBand->BDGraphicsBand = (PBYTE)ListEntry;
    hBand->BDTextBand     = FNULL;

    /******************************************************************/
    /* Set the fields in the bitmap list entry for the bitmap for the */
    /* current band.  The Band Origin in this case is equal to the    */
    /* bitmap origin because it is the bitmap for the band.  The      */
    /* XOrigin and YOrigin are used as translations to convert points */
    /* relative to the DC Origin to points relative to the bitmap     */
    /* origin.                                                        */
    /******************************************************************/
    ListEntry->BandXOrigin = hBand->BDCoords[0].X;
    ListEntry->BandYOrigin = hBand->BDCoords[0].Y;

    ListEntry->XOrigin = DCIData->DCIOrigin.X - hBand->BDCoords[0].X;
    ListEntry->YOrigin = DCIData->DCIOrigin.Y - hBand->BDCoords[0].Y;

    return (OK);
}





/**********************************************************************/
/*                                                                    */
/*   FUNCTION: prdj_FreeBand                                          */
/*                                                                    */
/*   PARAMETERS:                                                      */
/*                                                                    */
/*   lpDCI           DCIData;  Pointer to DC Instance data            */
/*   lpBand          hBand;    Pointer to band data                   */
/*                                                                    */
/*   DESCRIPTION:                                                     */
/*                                                                    */
/*   This function deletes the band specified in hBand, deleting the  */
/*   bitmap, freeing the associated memory and deselecting it in the  */
/*   DC Instance data and also deleting all items in the text band.   */
/*                                                                    */
/* Note: now frees a dummy list entry as well. (Q_STD/INFO DCs)       */
/**********************************************************************/
#if 0
USHORT pascal prdj_FreeBand ( DCIData,
                              hBand )

lpDCI           DCIData;
lpBand          hBand;
#endif

USHORT prdj_FreeBand ( lpDCI  DCIData,                     /* CON3201 */
                       lpBand hBand )                      /* CON3201 */

{
#define TFUNC "prdj_FreeBand"

    /******************************************************************/
    /* Local Variables                                                */
    /******************************************************************/
    lpGTBEntry    TextEntry;   /* Pointers for stepping through the   */
    lpGTBEntry    NextEntry;   /* text band to delete it              */
    pBMListEntry  lpBitmapLE;

    TRACE4(TFUNC, "Entry", FNULL, 0);
    TRACE4(TFUNC, "Band to be Freed", hBand, 4);

    /******************************************************************/
    /* If this is an INFO or QUEUED STD DC delete the dummy list entry*/
    /* In old code this was done in DisableDC - and MakeBand was only */
    /* called at CompleteOpen time. Now, MakeBand is always called.   */
    /******************************************************************/
    if ( DCIData->Flags & (QUEUED_STD | INFO) )
    {
        (void) prdg_FreeGlobalHeapItem(
                                LIST_ENTRY_SIZE,
                                (PUSHORT*)&DCIData->DCISelBitmap);
         return( OK );
    }

    /******************************************************************/
    /* Use prdb_DeleteBitmap and prdb_FreeBitmap on the current band  */
    /* bitmap.                                                        */
    /******************************************************************/
    if ( hBand->BDGraphicsBand != FNULL )
    {
        /**************************************************************/
        /* If the graphics band was selected in the DC Instance data  */
        /* then deselect it.                                          */
        /**************************************************************/
        TRACE4(TFUNC, "Deselect Bitmap in DC", FNULL, 0);

        if ( (DCIData->DCISelBitmap) &&
           (((pBMListEntry)DCIData->DCISelBitmap)->Bitmap ==
                        ((pBMListEntry)hBand->BDGraphicsBand)->Bitmap) )
        {
            TRACE4(TFUNC, "Deselect Bitmap in DC", FNULL, 0);
            DCIData->DCISelBitmap = FNULL;
        }

        /**************************************************************/
        /* Release the bitmap and the graphics band entry             */
        /**************************************************************/
        lpBitmapLE = (pBMListEntry)hBand->BDGraphicsBand;

        (void) prdb_FreeBitmap( lpBitmapLE->Bitmap );

        (void) prdb_DeleteBitmap( (pBMListEntry)hBand->BDGraphicsBand );

        /**************************************************************/
        /* Set the pointer to the graphics band to FNULL as it has    */
        /* been deleted.                                              */
        /**************************************************************/
        hBand->BDGraphicsBand = FNULL;
    }

    /******************************************************************/
    /* Free all the entries in the text band list by stepping through */
    /* the list using TextEntry and NextEntry and freeing all the     */
    /* memory allocated to them.                                      */
    /******************************************************************/
    TRACE4(TFUNC, "Free Text Entries", FNULL, 0);

    for ( TextEntry = hBand->BDTextBand; TextEntry != FNULL; )
    {
        /**************************************************************/
        /* Get the pointer to the next entry before we delete the     */
        /* current entry.                                             */
        /**************************************************************/
        NextEntry = TextEntry->GTBNextEntry;

        /**************************************************************/
        /* If there was memory allocated for character positions then */
        /* free it.                                                   */
        /* PD00076: GTBCharStartPos is PLONG. So change 2 to 4.       */
        /**************************************************************/
        if ( TextEntry->GTBCharStartPos  != FNULL )
        {
            (void) prdg_FreeHeapItem(
                         DCIData,
                         (4 * TextEntry->GTBCharPosAlloc),
                         (PUSHORT)(TextEntry->GTBCharStartPos) );
        }

        /**********************************************************************/
        /* PD00073 : GTBCharEndPos is not allocated for device Outline fonts, */
        /* so must add new if stmt to free only when it has been allocated.   */
        /**********************************************************************/
        if ( TextEntry->GTBCharEndPos  != FNULL )
        {
            (void) prdg_FreeHeapItem(
                         DCIData,
                         (2 * TextEntry->GTBCharPosAlloc),
                         (PUSHORT)(TextEntry->GTBCharEndPos)   );
        }

        /**********************************************************************/
        /* PD00073 : Delete strikeout memory for device outline fonts if it   */
        /* has been allocated in TextOutDevOutlineFont function.              */
        /* PD00076: changed GTBCharPosAlloc to GTBNumCdPts.    .              */
        /**********************************************************************/
        if ( TextEntry->GTBStrike  != FNULL )
        {
            (void) prdg_FreeHeapItem(
                         DCIData,
                         (sizeof(FOURPOINTL) * TextEntry->GTBNumCdPts),
                         (PUSHORT)(TextEntry->GTBStrike)   );
        }
        /**********************************************************************/
        /* Free this text band entry                                          */
        /**********************************************************************/
        (void) prdg_FreeHeapItem(
                         DCIData,
                         GTB_ENTRY_SIZE + TextEntry->GTBNumCdPts - 1,
                         (PUSHORT)TextEntry );

        TextEntry = NextEntry;
    }
    /******************************************************************/
    /* Set pointer to the text band to FNULL as it has been deleted.  */
    /******************************************************************/
    hBand->BDTextBand = FNULL;

    TRACE4(TFUNC, "Exit OK", FNULL, 0);
    return(OK);
}
#undef TFUNC





/**********************************************************************/
/*                                                                    */
/*   FUNCTION: prdj_UpdateBandCoordinates                             */
/*                                                                    */
/*   PARAMETERS:                                                      */
/*                                                                    */
/*   lpDCI           DCIData;  Pointer to DC Instance data            */
/*                                                                    */
/*   DESCRIPTION:                                                     */
/*                                                                    */
/*   This function updates the field containing the lower limit of    */
/*   band in the DC Instance data (BandLowY) and returns TRUE if this */
/*   is the last band.                                                */
/*                                                                    */
/**********************************************************************/
#if 0
BOOL pascal prdj_UpdateBandCoordinates ( DCIData )


lpDCI           DCIData;
#endif

BOOL prdj_UpdateBandCoordinates ( lpDCI DCIData )          /* CON3201 */

{
#define TFUNC "prdj_UpdBndCord"

    if ( DCIData->DCIPdbInstance->Orientation == PORTRAIT )
    {
        /**************************************************************/
        /* In portrait mode BandLowY is counted from the bottom of    */
        /* the page so it is the y coordinate of the bottom corner of */
        /* the current band.                                          */
        /**************************************************************/
        DCIData->DCIBandLowY = DCIData->DCICurrBand.BDCoords[0].Y;

        /**************************************************************/
        /* Check whether this is the last band.                       */
        /**************************************************************/
        if ( DCIData->DCIBandLowY <= DCIData->DCIJournLowY )
            return(TRUE);
    }

    else /* LANDSCAPE */
    {
        /**************************************************************/
        /* In LANDSCAPE mode BandLowY is counted from the top of the  */
        /* page so it is the x coordinate of the top right corner of  */
        /* the current band.                                          */
        /**************************************************************/
        DCIData->DCIBandLowY = DCIData->DCICurrBand.BDCoords[1].X;

        /**************************************************************/
        /* Check whether it is the last band.                         */
        /**************************************************************/
        if (DCIData->DCIBandLowY >= DCIData->DCIJournLowY)
            return(TRUE);

    } /* LANDSCAPE */

    return(FALSE);

} /* prdj_UpdateBandCoordinates */

#undef TFUNC


/**********************************************************************/
/*                                                                    */
/*   FUNCTION: prdj_LastBand                                          */
/*                                                                    */
/*   PARAMETERS:                                                      */
/*                                                                    */
/*   lpDCI           DCIData;  Pointer to DC Instance data            */
/*                                                                    */
/*   DESCRIPTION:                                                     */
/*                                                                    */
/*   This function returns TRUE if this is the last band.             */
/*                                                                    */
/**********************************************************************/
#if 0
BOOL pascal prdj_LastBand ( DCIData )


lpDCI           DCIData;
#endif

BOOL prdj_LastBand ( lpDCI DCIData )                       /* CON3201 */

{

    if ( DCIData->DCIPdbInstance->Orientation == PORTRAIT )
    {
        /**************************************************************/
        /* In portrait mode BandLowY is counted from the bottom of    */
        /* the page so it is the y coordinate of the bottom corner of */
        /* the current band.                                          */
        /**************************************************************/
        if ( DCIData->DCICurrBand.BDCoords[0].Y <=
             DCIData->DCIJournLowY )
            return(TRUE);
    }
    else /* LANDSCAPE */
    {
        /**************************************************************/
        /* In LANDSCAPE mode BandLowY is counted from the top of the  */
        /* page so it is the x coordinate of the top right corner of  */
        /* the current band.                                          */
        /**************************************************************/
        if ( DCIData->DCICurrBand.BDCoords[1].X >=
             DCIData->DCIJournLowY )
            return(TRUE);

    } /* LANDSCAPE */

    return(FALSE);

} /* prdj_LastBand */


