File:  [WindowsNT SDKs] / ntddk / src / video / displays / vga / stroke.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Thu Aug 9 18:31:12 2018 UTC (7 years, 9 months ago) by root
Branches: msft, MAIN
CVS tags: ntddk-nov-1993, HEAD
Microsoft Windows NT Build 511 (DDK SDK) 11-01-1993

/******************************Module*Header*******************************\
* Module Name: Stroke.c
*
* DrvStrokePath for VGA driver
*
* Copyright (c) 1992 Microsoft Corporation
\**************************************************************************/

#include "driver.h"

#include "lines.h"

// External calls

VOID vSetStrips(ULONG, ULONG);
VOID vClearStrips(ULONG);

#define MIN(A,B)    ((A) < (B) ? (A) : (B))

// Prototypes to go to the screen:

VOID vStripSolidHorizontal(STRIP*, LINESTATE*, LONG*);
VOID vStripSolidHorizontalSet(STRIP*, LINESTATE*, LONG*);
VOID vStripSolidVertical(STRIP*, LINESTATE*, LONG*);
VOID vStripSolidDiagonalHorizontal(STRIP*, LINESTATE*, LONG*);
VOID vStripSolidDiagonalVertical(STRIP*, LINESTATE*, LONG*);

VOID vStripStyledHorizontal(STRIP*, LINESTATE*, LONG*);
VOID vStripStyledVertical(STRIP*, LINESTATE*, LONG*);

VOID vStripMaskedHorizontal(STRIP*, LINESTATE*, LONG*);
VOID vStripMaskedVertical(STRIP*, LINESTATE*, LONG*);

PFNSTRIP gapfnStripSolidSet[] = {

// Special strip drawers for solid lines with SET style ROPs:

    vStripSolidHorizontalSet,
    vStripSolidVertical,
    vStripSolidDiagonalHorizontal,
    vStripSolidDiagonalVertical
};

PFNSTRIP gapfnStrip[] = {

// The order of these first 3 sets of strip drawers is determined by
// the FL_STYLE_MASK bits of the line flags:

    vStripSolidHorizontal,
    vStripSolidVertical,
    vStripSolidDiagonalHorizontal,
    vStripSolidDiagonalVertical,

    vStripStyledHorizontal,
    vStripStyledVertical,
    NULL,    // Diagonal goes here
    NULL,    // Diagonal goes here

    vStripMaskedHorizontal,
    vStripMaskedVertical,
    NULL,    // Diagonal goes here
    NULL,    // Diagonal goes here
};

// Prototypes to go to a device-format bitmap:

VOID vBitmapSolidHorizontal(STRIP*, LINESTATE*, LONG*);
VOID vBitmapSolidVertical(STRIP*, LINESTATE*, LONG*);
VOID vBitmapSolidDiagonal(STRIP*, LINESTATE*, LONG*);

VOID vBitmapStyledHorizontal(STRIP*, LINESTATE*, LONG*);
VOID vBitmapStyledVertical(STRIP*, LINESTATE*, LONG*);

// For two-pass ROPs:

VOID vCatchTwoPass(STRIP*, LINESTATE*, LONG*);

PFNSTRIP gapfnCatchTwoPass[] = {
    vCatchTwoPass,
    vCatchTwoPass,
    vCatchTwoPass,
    vCatchTwoPass
};

// VGA ulVgaMode constants:

#define DR_SET   0x00
#define DR_AND   0x08
#define DR_OR    0x10
#define DR_XOR   0x18

// Bit flag set if two passes needed:

#define DR_2PASS 0x80

// Table to convert ROP to usable information:

static struct {
    ULONG ulColorAnd;
    ULONG ulColorXor;
    ULONG ulVgaMode;
} arop[] = {
    {0x00, 0xff, DR_SET},          //  1   R2_WHITE
    {0x00, 0x00, DR_SET},          //  0   R2_BLACK
    {0xff, 0xff, DR_AND|DR_2PASS}, // DPon R2_NOTMERGEPEN   Dest invert + DPna
    {0xff, 0xff, DR_AND},          // DPna R2_MASKNOTPEN
    {0xff, 0xff, DR_SET},          // PN   R2_NOTCOPYPEN
    {0xff, 0x00, DR_AND|DR_2PASS}, // PDna R2_MASKPENNOT    Dest invert + DPa
    {0x00, 0xff, DR_XOR},          // Dn   R2_NOT           Invert dest without pen
    {0xff, 0x00, DR_XOR},          // DPx  R2_XORPEN
    {0xff, 0xff, DR_OR|DR_2PASS},  // DPan R2_NOTMASKPEN    Dest invert + DPno
    {0xff, 0x00, DR_AND},          // DPa  R2_MASKPEN
    {0xff, 0xff, DR_XOR},          // DPxn R2_NOTXORPEN     DPxn == DPnx
    {0x00, 0x00, DR_OR},           // D    R2_NOP           Silliness!
    {0xff, 0xff, DR_OR},           // DPno R2_MERGENOTPEN
    {0xff, 0x00, DR_SET},          // P    R2_COPYPEN
    {0xff, 0x00, DR_OR|DR_2PASS},  // PDno R2_MERGEPENNOT   Dest invert + DPo
    {0xff, 0x00, DR_OR},           // DPo  R2_MERGEPEN
};

// The gaulAndXorTable contains and-masks and xor-masks for setting
// pels to one of four possible values.  The and-masks have been
// inverted, and are stored in the low byte of each word.  The
// xor-masks are stored in the high bytes.
//
//      ROP     XOR    ~AND
//      -------------------
//      DDx     00      FF        Set to zero
//      Dn      FF      00        Not destination
//      D       00      00        Leave alone
//      DDxn    FF      FF        Set to one

ULONG gaulAndXorTable[] = {
    0x00ff,     // Set to zero
    0xff00,     // Not destination
    0x0000,     // Leave alone
    0xffff      // Set to one
};

ULONG gaulInitMasksLtoR[] = { 0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f };
ULONG gaulInitMasksRtoL[] = { 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe };

/******************************Public*Routine******************************\
* BOOL DrvStrokePath(pso, ppo, pco, pxo, pbo, pptlBrushOrg, pla, mix)
*
* Strokes the path.
*
\**************************************************************************/

BOOL DrvStrokePath(
SURFOBJ*   pso,
PATHOBJ*   ppo,
CLIPOBJ*   pco,
XFORMOBJ*  pxo,
BRUSHOBJ*  pbo,
POINTL*    pptlBrushOrg,
LINEATTRS* pla,
MIX        mix)
{
    STYLEPOS  aspLtoR[STYLE_MAX_COUNT];
    STYLEPOS  aspRtoL[STYLE_MAX_COUNT];
    LINESTATE ls;
    PFNSTRIP* apfn;
    FLONG     fl;
    PDEVSURF  pdsurf;
    ULONG     ulVgaMode;

    UNREFERENCED_PARAMETER(pxo);
    UNREFERENCED_PARAMETER(pptlBrushOrg);

// Verify that things are as they should be:

//    ASSERT(pso != (SURFOBJ*) NULL,  "DrvStrokePath: surface");
//    ASSERT(ppo != (PATHOBJ*) NULL,  "DrvStrokePath: path");
//    ASSERT(pco != (CLIPOBJ*) NULL,  "DrvStrokePath: clipobj");
//    ASSERT(pbo != (BRUSHOBJ*) NULL, "DrvStrokePath: brushobj");
//    ASSERT(pla != (LINEATTRS*) NULL && !(pla->fl & LA_GEOMETRIC),
//                                     "DrvStrokePath: lineattrs");
//    ASSERT(pbo->iSolidColor != 0xffffffff,
//                                     "DrvStrokePath: brushobj isn't solid");

// Get the device ready:

    pdsurf = (PDEVSURF) pso->dhsurf;
//    ASSERT(pdsurf != (PDEVSURF) NULL, "DrvStrokePath: no surface");

    fl = 0;

// Look after styling initialization:

    if (pla->fl & LA_ALTERNATE)
    {
//        ASSERT(pla->pstyle == (FLOAT_LONG*) NULL && pla->cstyle == 0,
//               "Non-empty style array for PS_ALTERNATE");

        ls.spTotal     = 1;
        ls.spTotal2    = 2;
        ls.xyDensity   = 1;
        fl            |= (FL_ALTERNATESTYLED | FL_MASKSTYLED);
    }
    else if (pla->pstyle != (FLOAT_LONG*) NULL)
    {
        PFLOAT_LONG pstyle;

//        ASSERT(pla->cstyle <= STYLE_MAX_COUNT, "Style array too large");

        pstyle = &pla->pstyle[pla->cstyle];

        ls.xyDensity = STYLE_DENSITY;
        ls.spTotal   = 0;
        while (pstyle-- > pla->pstyle)
        {
            ls.spTotal += pstyle->l;
        }
        ls.spTotal *= STYLE_DENSITY;
        ls.spTotal2 = 2 * ls.spTotal;

    // Compute starting style position (this is guaranteed not to overflow):

        ls.spNext = HIWORD(pla->elStyleState.l) * STYLE_DENSITY +
                    LOWORD(pla->elStyleState.l);

    // We optimize the style arrays that are even length and sum to 8.  We
    // also don't have any masked strip drawers for DFBs:

        if (ls.spTotal == (8 * STYLE_DENSITY) &&
            (pla->cstyle & 1) == 0)
        {
        // Do "masked" styles.
        // -------------------
        //
        // This case is merely an optimization; you can remove it and
        // all style lines will still work.  It just so happens that the
        // default styles (such as PS_DOT, PS_DASHDOT, etc.) will all
        // sum to 8, and there are some optimizations we can do on the
        // VGA for that case.
        //
        // We make an 8 bit mask that represents each style unit in the
        // style array, and we pass this to the "Masked" strip drawers
        // (instead of calling the "Styled" strip drawers which still
        // handle the arbitrary styles).

            LONG ii;

            ls.ulStyleMaskLtoR = 0;
            ls.ulStyleMaskRtoL = 0;

            for (pstyle = pla->pstyle, ii = 8; ii > 0;)
            {
                LONG l1 = (pstyle++)->l;
                LONG l2 = (pstyle++)->l;

                ls.ulStyleMaskRtoL >>= l1 + l2;
                ls.ulStyleMaskRtoL |= gaulInitMasksRtoL[l2];

                ls.ulStyleMaskLtoR <<= l1 + l2;
                ls.ulStyleMaskLtoR |= gaulInitMasksLtoR[l2];

                ii -= (l1 + l2);
            }

        // Replicate byte and initialize to style position zero:

            ls.ulStyleMaskLtoR |= (ls.ulStyleMaskLtoR << 8);
            ls.ulStyleMaskLtoR |= (ls.ulStyleMaskLtoR << 16);

            ls.ulStyleMaskRtoL |= (ls.ulStyleMaskRtoL << 8);
            ls.ulStyleMaskRtoL |= (ls.ulStyleMaskRtoL << 16);

        // Check if we should start with a gap or start with a dash:

            if (pla->fl & LA_STARTGAP)
            {
                ls.ulStyleMaskLtoR = ~ls.ulStyleMaskLtoR;
                ls.ulStyleMaskRtoL = ~ls.ulStyleMaskRtoL;
            }

        // Initialize some other state:

            fl |= FL_MASKSTYLED;
        }
        else

    // Okay, we've got to do it the slow way:

        {
        // Handle Arbitrary Styles
        // -----------------------
        //
        // Because arbitrary styles are new to Win32, many apps won't
        // know about them and will use the default styles (which will
        // be handled by the "Masked" optimization case above), and so
        // this code path won't get exercised too often.  (See GDI's
        // ExtCreatePen API.)
        //
        // But you still have to handle them, and do them right!

            FLOAT_LONG* pstyle;
            STYLEPOS*   pspDown;
            STYLEPOS*   pspUp;

            fl        |= FL_ARBITRARYSTYLED;
            ls.cStyle  = pla->cstyle;
            ls.aspRtoL = aspRtoL;
            ls.aspLtoR = aspLtoR;

            if (pla->fl & LA_STARTGAP)
                ls.ulStartMask = 0xffffffffL;
            else
                ls.ulStartMask = 0L;

            pstyle  = pla->pstyle;
            pspDown = &ls.aspRtoL[ls.cStyle - 1];
            pspUp   = &ls.aspLtoR[0];

        // We always draw strips left-to-right, but styles have to be laid
        // down in the direction of the original line.  This means that in
        // the strip code we have to traverse the style array in the
        // opposite direction;

            while (pspDown >= &ls.aspRtoL[0])
            {
//                ASSERT(pstyle->l > 0 && pstyle->l <= STYLE_MAX_VALUE,
//                       "Illegal style array value");

                *pspDown = pstyle->l * STYLE_DENSITY;
                *pspUp   = *pspDown;

                pspUp++;
                pspDown--;
                pstyle++;
            }
        }
    }

    {
        ULONG iColor;
        ULONG iStripIndex;

        fl |= FL_PHYSICAL_DEVICE;

    // Compute the pointer to the correct strip drawing table.  We
    // have a special table for solid lines done with VGA mode == SET:

        iStripIndex = 4 * ((fl & FL_STYLE_MASK) >> FL_STYLE_SHIFT);
        apfn = &gapfnStrip[iStripIndex];

        mix &= 0xf;
        ulVgaMode = arop[mix].ulVgaMode;

        if (ulVgaMode == DR_SET && iStripIndex == 0)
            apfn = &gapfnStripSolidSet[0];

    // Compute the correct color, based on the ROP we're doing:

        iColor = (pbo->iSolidColor & arop[mix].ulColorAnd)
               ^ (arop[mix].ulColorXor);

        if (!(ulVgaMode & DR_2PASS))
            vSetStrips(iColor, ulVgaMode);
        else
        {
        // If the ROP requires 2 passes, we sneakily change our strip
        // table pointer to point to only our own routine, and it
        // handles calling the appropriate strip routines twice:

            ls.ulVgaMode = ulVgaMode ^ DR_2PASS;
            ls.iColor    = iColor;
            ls.apfnStrip = apfn;
            apfn         = gapfnCatchTwoPass;
        }
    }

// Set up to enumerate the path:

    if (pco->iDComplexity != DC_COMPLEX)
    {
        RECTL     arclClip[4];                   // For rectangular clipping
        PATHDATA  pd;
        RECTL*    prclClip = (RECTL*) NULL;
        BOOL      bMore;
        ULONG     cptfx;
        POINTFIX  ptfxStartFigure;
        POINTFIX  ptfxLast;
        POINTFIX* pptfxFirst;
        POINTFIX* pptfxBuf;

        if (pco->iDComplexity == DC_RECT)
        {
            fl |= FL_SIMPLE_CLIP;

            arclClip[0]        =  pco->rclBounds;

        // FL_FLIP_D:

            arclClip[1].top    =  pco->rclBounds.left;
            arclClip[1].left   =  pco->rclBounds.top;
            arclClip[1].bottom =  pco->rclBounds.right;
            arclClip[1].right  =  pco->rclBounds.bottom;

        // FL_FLIP_V:

            arclClip[2].top    = -pco->rclBounds.bottom + 1;
            arclClip[2].left   =  pco->rclBounds.left;
            arclClip[2].bottom = -pco->rclBounds.top + 1;
            arclClip[2].right  =  pco->rclBounds.right;

        // FL_FLIP_V | FL_FLIP_D:

            arclClip[3].top    =  pco->rclBounds.left;
            arclClip[3].left   = -pco->rclBounds.bottom + 1;
            arclClip[3].bottom =  pco->rclBounds.right;
            arclClip[3].right  = -pco->rclBounds.top + 1;

            prclClip = arclClip;
        }

        PATHOBJ_vEnumStart(ppo);

        do {
            bMore = PATHOBJ_bEnum(ppo, &pd);

            cptfx = pd.count;
            if (cptfx == 0)
            {
//                ASSERT(!bMore, "Empty path record in non-empty path");
                break;
            }

            if (pd.flags & PD_BEGINSUBPATH)
            {
                ptfxStartFigure  = *pd.pptfx;
                pptfxFirst       = pd.pptfx;
                pptfxBuf         = pd.pptfx + 1;
                cptfx--;
            }
            else
            {
                pptfxFirst       = &ptfxLast;
                pptfxBuf         = pd.pptfx;
            }

            if (pd.flags & PD_RESETSTYLE)
                ls.spNext = 0;

        // We have to check for cptfx == 0 because the only point in the
        // subpath may have been the StartFigure point:

            if (cptfx > 0)
            {
                if (!bLines(pdsurf,
                            pptfxFirst,
                            pptfxBuf,
                            (RUN*) NULL,
                            cptfx,
                            &ls,
                            prclClip,
                            apfn,
                            fl))
                    return(FALSE);
            }

            ptfxLast = pd.pptfx[pd.count - 1];

            if (pd.flags & PD_CLOSEFIGURE)
            {
                if (!bLines(pdsurf,
                            &ptfxLast,
                            &ptfxStartFigure,
                            (RUN*) NULL,
                            1,
                            &ls,
                            prclClip,
                            apfn,
                            fl))
                    return(FALSE);
            }
        } while (bMore);

        if (fl & FL_STYLED)
        {
        // Save the style state:

            ULONG ulHigh;
            ULONG ulLow;

        // !!! The engine handles unnormalized style states.  This can
        // !!! be removed.  Might have to remove some asserts in the
        // !!! engine.

        // Masked styles don't normalize the style state.  It's a good
        // thing to do, so let's do it now:

            if ((ULONG) ls.spNext >= (ULONG) ls.spTotal2)
                ls.spNext = (ULONG) ls.spNext % (ULONG) ls.spTotal2;

            ulHigh = ls.spNext / ls.xyDensity;
            ulLow  = ls.spNext % ls.xyDensity;

            pla->elStyleState.l = MAKELONG(ulLow, ulHigh);
        }
    }
    else
    {
    // Local state for path enumeration:

        BOOL bMore;
        union {
            BYTE     aj[offsetof(CLIPLINE, arun) + RUN_MAX * sizeof(RUN)];
            CLIPLINE cl;
        } cl;

        fl |= FL_COMPLEX_CLIP;

    // We use the clip object when non-simple clipping is involved:

        PATHOBJ_vEnumStartClipLines(ppo, pco, pso, pla);

        do {
            bMore = PATHOBJ_bEnumClipLines(ppo, sizeof(cl), &cl.cl);
            if (cl.cl.c != 0)
            {
                if (fl & FL_STYLED)
                {
                    ls.spComplex = HIWORD(cl.cl.lStyleState) * ls.xyDensity
                                 + LOWORD(cl.cl.lStyleState);
                }
                if (!bLines(pdsurf,
                            &cl.cl.ptfxA,
                            &cl.cl.ptfxB,
                            &cl.cl.arun[0],
                            cl.cl.c,
                            &ls,
                            (RECTL*) NULL,
                            apfn,
                            fl))
                    return(FALSE);
            }
        } while (bMore);
    }

    if (fl & FL_PHYSICAL_DEVICE)
        vClearStrips(ulVgaMode);

    return(TRUE);
}

/******************************Public*Routine******************************\
* VOID vCatchTwoPass(pstrip, pls, plStripEnd)
*
* Handles ROPs that cannot be done in a single pass using the VGA
* hardware.  In order not to have a check in our main drawing loop for
* two-pass ROPs, we change the strip function table so that this function
* intercepts the call to draw the strips.
*
* This routine then figures out the appropriate actual strip drawer, and
* makes two calls to it: first to invert the destination, then to do the
* rest of the ROP.
*
\**************************************************************************/

VOID vCatchTwoPass(STRIP* pstrip, LINESTATE* pls, LONG* plStripEnd)
{
    BYTE*     pjScreen    = pstrip->pjScreen;
    BYTE      jBitMask    = pstrip->jBitMask;
    BYTE      jStyleMask  = pstrip->jStyleMask;
    STYLEPOS* psp         = pstrip->psp;
    STYLEPOS  spRemaining = pstrip->spRemaining;

// Figure out the actual strip routine we're supposed to call:

    PFNSTRIP pfn = pls->apfnStrip[(pstrip->flFlips & FL_STRIP_MASK) >>
                                  FL_STRIP_SHIFT];

// On the first pass, we invert the destination:

    vSetStrips(0xff, DR_XOR);

    (*pfn)(pstrip, pls, plStripEnd);

// We reset our strip variables for the second pass and handle the rest
// of the ROP:

    pstrip->pjScreen    = pjScreen;
    pstrip->jBitMask    = jBitMask;
    pstrip->jStyleMask  = jStyleMask;
    pstrip->psp         = psp;
    pstrip->spRemaining = spRemaining;

    vSetStrips(pls->iColor, pls->ulVgaMode);

    (*pfn)(pstrip, pls, plStripEnd);
}


unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.