/*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.                                */
/*                                                                           */
/*****************************************************************************/
/**********************************************************************/
/*                                                                    */
/*   Module          = EDDTPSUB                                       */
/*                                                                    */
/*   Description     = Display Device Driver text subfunctions        */
/*                     GetTextBox                                     */
/*                     ConvertIncVector                               */
/*                                                                    */
/*   Function        =                                                */
/*                                                                    */
/*   Reference       = Winthorn Functional Specification              */
/*                     Device Driver Interface Specification          */
/*                     Display Device Driver Design Specification     */
/*                                                                    */
/*                                                                    */
/**********************************************************************/
#define INCL_DDIFONTSTRUCS
#define INCL_DDIMISC
#define INCL_GRE_FONTS
#define INCL_DDICOMFLAGS
#define INCL_GRE_XFORMS
#include <eddinclt.h>

#include <edddtypt.h>
#include <eddtcone.h>
#include <eddttypt.h>
#include <eddtextf.h>
#include <eddcextf.h>
#include <eddacone.h>

extern PPFNL            EnginesDispatchTable;
extern AIWORK           AIWork;

/**********************************************************************/
/* GetTextBox calculates the bounding rectangle which would surround  */
/* the codepoints passed in as input parameters. The required start   */
/* position for the string is input as the first coordinate of the    */
/* bounding rectangle.                                                */
/**********************************************************************/

VOID eddt_GetTextBox (USHORT        Charnum,
                      PUCHAR        CodePoints,
                      PSHORT        Vector,
                      PDC           pdcBox)

{
    /******************************************************************/
    /* Local variables                                                */
    /******************************************************************/
    PBYTE              pPerCharDefs;   /* Pointer to base char defns  */
    PCHAR_DEFN         pCharDefn;      /* Pointer to char defn        */
    USHORT             usCellSize;     /* Per character def size      */
    USHORT             usFirstChar;    /* Code point of first char    */
    PUSHORT            EnvelopeTab;    /* Pointer to envelope table   */
    USHORT             usGlyphIndex;   /* The current glyph index     */
    PFOCAFONT          pFocaFont;
    USHORT             saveCharnum;


    register SHORT     CurrPosX;


    /******************************************************************/
    /* Evaluate horizontal bounds                                     */
    /******************************************************************/
    CurrPosX = AIWork.Bound[0].X;
    saveCharnum = Charnum;

    if (Vector)
    {
        /**************************************************************/
        /* we have a position vector which tells us where to place    */
        /* each character, and also where the new current position    */
        /* will be after the string has been drawn                    */
        /* We used to use the new current position as the bounds      */
        /* but the IFI uses position vectors where the new current    */
        /* position increment is 0 - ie the new current position is   */
        /* left at the start of the last character in the string      */
        /* this means that we draw the last character outside the     */
        /* bounds that we return                                      */
        /* Thus it seems we need to use the position vector to work   */
        /* out where the last character starts, and then add on the   */
        /* width of the last character                                */
        /*                                                            */
        /* First sum all but the last position vector to determine    */
        /* where the last character starts                            */
        /**************************************************************/
        for ( Charnum; Charnum>1; Charnum--,CodePoints++)
        {
            CurrPosX += *Vector++;
        }
        /**************************************************************/
        /* note we have decremented Charnum to 1                      */
        /* and moved CodePoints to point at the last codepoint        */
        /**************************************************************/
        /**************************************************************/
        /* NB if we shouldn't apply the charSpacing to position       */
        /* vectors then just make this zero.                          */
        /**************************************************************/
        saveCharnum = 1 ;
    }

    /******************************************************************/
    /* at this point we either have no increment vector supplied      */
    /* or else we have the last character left to process at the      */
    /* end of the increment vector                                    */
    /******************************************************************/
    pFocaFont = pdcBox->CurrentFont.pFocaFont;

    /******************************************************************/
    /* Set vertical bounds                                            */
    /******************************************************************/
    AIWork.Bound[1].Y = AIWork.Bound[0].Y +
                               pFocaFont->fdDefinitions.yCellHeight;

    /******************************************************************/
    /* The font is FocaFont format, which can be fixed pitch,         */
    /* proportional spaced or abc spaced.                             */
    /******************************************************************/
    if (pdcBox->DCISpacingType == FIXED_PITCH)
    {
        /**************************************************************/
        /* Font is fixed pitch FocaFont.                              */
        /**************************************************************/
        CurrPosX += pFocaFont->fdDefinitions.xCellWidth  * Charnum;
    }
    else
    {
        /**************************************************************/
        /* Font is proportional or abc spaced FocaFont.               */
        /**************************************************************/
        pPerCharDefs = (PBYTE)pdcBox->CurrentFont.pFocaFont +
                                                   sizeof(FOCAFONT);
        usCellSize = pFocaFont->fdDefinitions.usCellSize;
        usFirstChar = pFocaFont->fmMetrics.usFirstChar;

        for ( ; Charnum; Charnum--)
        {
            /**********************************************************/
            /* Convert codepoint via codepage if necessary.           */
            /**********************************************************/
            if (pdcBox->CurrentFont.pCodePageVector)
            {
                usGlyphIndex = pdcBox->CurrentFont.
                                     pCodePageVector[*CodePoints++];
            }
            else
            {
                usGlyphIndex = *CodePoints++;
            }

            /**********************************************************/
            /* Now validate the glyph index, and make it relative to  */
            /* the first character of the font.                       */
            /**********************************************************/
            if ( (usGlyphIndex <
                                pFocaFont->fmMetrics.usFirstChar) ||
                 (usGlyphIndex >
                        (pFocaFont->fmMetrics.usLastChar +
                                pFocaFont->fmMetrics.usFirstChar)) )
            {
                /******************************************************/
                /* The glyph index is invalid.  Use the default char  */
                /* from the metrics.  Note that this value is         */
                /* relative to the first char in the font (which is   */
                /* what we want).                                     */
                /******************************************************/
                usGlyphIndex = pFocaFont->fmMetrics.usDefaultChar;
            }
            else
            {
                /******************************************************/
                /* The glyph index is valid.  Adjust it so that it is */
                /* relative to the first character in the font.       */
                /******************************************************/
                usGlyphIndex -= pFocaFont->fmMetrics.usFirstChar;
            }

            /**********************************************************/
            /* Get a pointer to the char definition for the current   */
            /* character.                                             */
            /**********************************************************/
            pCharDefn = (PBYTE)pPerCharDefs +
                                    (usCellSize * usGlyphIndex);

            if (pdcBox->DCISpacingType == PROPORTIONAL_SPACED)
            {
                /******************************************************/
                /* Proportional spaced - use the char width           */
                /******************************************************/
                CurrPosX += pCharDefn->nonabcDefn.usCharWidth;
            }
            else
            {
                /******************************************************/
                /* ABC spaced - use the sum of the abc spaces         */
                /******************************************************/
                CurrPosX += (pCharDefn->abcDefn.usASpace) +
                            (pCharDefn->abcDefn.usBSpace) +
                            (pCharDefn->abcDefn.usCSpace) ;
            }
        }
    }

    /******************************************************************/
    /* Allow for charSpacing                                          */
    /******************************************************************/
    CurrPosX += saveCharnum * pdcBox->DCICurTxtAts.cdef.charSpacing;
    /******************************************************************/
    /* Accumulate Bounds                                              */
    /******************************************************************/
    AIWork.Bound[1].X = CurrPosX;
}

/**********************************************************************/
/* eddt_ConvertIncVector                                              */
/* The increment vector is passed as an array of World x-coordinates. */
/* This function converts it to an array of Device x-coordinates.     */
/**********************************************************************/
USHORT eddt_ConvertIncVector(PSHORT  DevVector,
                             USHORT  NumVec,
                             PLONG   WldVector)
{

#define BATCH 32  /* process 32 coordinates at a time */

    POINTL  Points[BATCH+1];     /* temp store of batch of coords */
    ULONG   NPoints;             /* number of points in a batch   */
    ULONG   ulCount;
    SHORT   cumOffset;

    /******************************************************************/
    /* If simple transformation, no need to convert, just copy...     */
    /******************************************************************/
    if ( pdc->DCIXFrmSimple )
    {
        for (; NumVec ; NumVec-- )
        {
            *DevVector++ = (SHORT) *WldVector++;
        }
        return(OK);
    }

    /******************************************************************/
    /* Loop for each batch of coords                                  */
    /******************************************************************/
    while (NumVec)
    {
        /**************************************************************/
        /* Determine size of batch                                    */
        /* - minimum of batch size and number remaining               */
        /* - decrement number remaining                               */
        /**************************************************************/
        NPoints = min( NumVec, BATCH );
        NumVec -= NPoints;

        /**************************************************************/
        /* Must set Y-coord to zero for conversion.                   */
        /* Do this by clearing the whole lot to zero.                 */
        /**************************************************************/
        memset( (PVOID)Points, 0, sizeof(POINTL)*(BATCH+1) );

        /**************************************************************/
        /* Set the cumulative offset to zero to start with            */
        /**************************************************************/
        cumOffset = 0 ;

        /**************************************************************/
        /* Set up the array as an array of points (with y=0) and x    */
        /* determined by adding each position vector from the input   */
        /**************************************************************/
        for ( ulCount = 1 ; ulCount <= NPoints ; ulCount++)
        {
            cumOffset += (SHORT) *WldVector++ ;
            Points[ulCount].x = cumOffset ;
        }

        /**************************************************************/
        /* Now can convert the coords                                 */
        /**************************************************************/
        if ( ! EnginesDispatchTable[NGreConvert & 0xff](
                                                     pdc->DCIhdc,
                                                     CVTC_WORLD,
                                                     CVTC_DEVICE,
                                                     (PPOINTL)Points,
                                                     NPoints+1,
                                                     NULL,
                                                     NGreConvert )
           )
        {
            return ERROR_ZERO;
        }

        /**************************************************************/
        /* Copy the converted x-coords to the destination vector      */
        /**************************************************************/
        for (ulCount=1; ulCount <= NPoints; ulCount++)
        {
            *DevVector++ = (SHORT)(Points[ulCount].x - Points[ulCount-1].x) ;
        }

    } /* while NumVec */

    return OK;
}
