Ejemplo n.º 1
0
BOOL DrvStrokePath(
    SURFOBJ*   pso,
    PATHOBJ*   ppo,
    CLIPOBJ*   pco,
    XFORMOBJ*  pxo,
    BRUSHOBJ*  pbo,
    POINTL*    pptlBrush,
    LINEATTRS* pla,
    MIX        mix)
{
    STYLEPOS  aspLtoR[STYLE_MAX_COUNT];
    STYLEPOS  aspRtoL[STYLE_MAX_COUNT];
    LINESTATE ls;
    PFNSTRIP* apfn;
    FLONG     fl;
    PDEV*     ppdev;
    DSURF*    pdsurf;
    OH*       poh;
    ULONG     ulHwMix;
    RECTL     arclClip[4];                  // For rectangular clipping
    RECTL     rclBounds;
    RECTFX    rcfxBounds;

// Pass the surface off to GDI if it's a device bitmap that we've
// converted to a DIB:

    pdsurf = (DSURF*) pso->dhsurf;
    if (pdsurf->dt == DT_DIB)
    {
        return(EngStrokePath(pdsurf->pso, ppo, pco, pxo, pbo, pptlBrush,
                             pla, mix));
    }

// We'll be drawing to the screen or an off-screen DFB; copy the surface's
// offset now so that we won't need to refer to the DSURF again:

    poh   = pdsurf->poh;
    ppdev = (PDEV*) pso->dhpdev;
    ppdev->xOffset = poh->x;
    ppdev->yOffset = poh->y;

    ulHwMix = gajHwMixFromMix[mix & 0xf];

// x86 has special case ASM code for accelerating solid lines:

#if defined(_X86_)

    if ((pla->pstyle == NULL) && !(pla->fl & LA_ALTERNATE))
    {
    // We can accelerate solid lines:

        if (pco->iDComplexity == DC_TRIVIAL)
        {
            ppdev->pfnFastLine(ppdev, ppo, NULL, &gapfnStrip[0], 0,
                               pbo->iSolidColor, ulHwMix);

            return(TRUE);
        }
        else if (pco->iDComplexity == DC_RECT)
        {
        // We have to be sure that we don't overflow the hardware registers
        // for current position, line length, or DDA terms.  We check
        // here to make sure that the current position and line length
        // values won't overflow (for integer lines, this check is
        // sufficient to ensure that the DDA terms won't overflow; for GIQ
        // lines, we specifically check on every line in pfnFastLine that we
        // don't overflow).

            PATHOBJ_vGetBounds(ppo, &rcfxBounds);

            if (rcfxBounds.xLeft   + (ppdev->xOffset * F)
                                                >= (MIN_INTEGER_BOUND * F) &&
                rcfxBounds.xRight  + (ppdev->xOffset * F)
                                                <= (MAX_INTEGER_BOUND * F) &&
                rcfxBounds.yTop    + (ppdev->yOffset * F)
                                                >= (MIN_INTEGER_BOUND * F) &&
                rcfxBounds.yBottom + (ppdev->yOffset * F)
                                                <= (MAX_INTEGER_BOUND * F))
            {
            // Since we're going to be using the scissors registers to
            // do hardware clipping, we'll also have to make sure we don't
            // exceed its bounds.  ATI chips have a maximum limit of 1023,
            // which we could exceed if we're running at 1280x1024, or for
            // off-screen device bitmaps.

                if ((pco->rclBounds.right  + ppdev->xOffset < 1024) &&
                    (pco->rclBounds.bottom + ppdev->yOffset < 1024))
                {
                    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;

                    rclBounds.left   = pco->rclBounds.left;
                    rclBounds.top    = pco->rclBounds.top;
                    rclBounds.right  = pco->rclBounds.right;
                    rclBounds.bottom = pco->rclBounds.bottom;

                    vSetClipping(ppdev, &rclBounds);

                    ppdev->pfnFastLine(ppdev, ppo, &arclClip[0], &gapfnStrip[0],
                                       FL_SIMPLE_CLIP, pbo->iSolidColor, ulHwMix);

                    vResetClipping(ppdev);
                    return(TRUE);
                }
            }
        }
    }

#endif // _X86_

// Get the device ready:

    if (DEPTH32(ppdev))
    {
        IO_FIFO_WAIT(ppdev, 4);
        MM_FRGD_COLOR32(ppdev, ppdev->pjMmBase, pbo->iSolidColor);
    }
    else
    {
        IO_FIFO_WAIT(ppdev, 3);
        IO_FRGD_COLOR(ppdev, pbo->iSolidColor);
    }

    IO_FRGD_MIX(ppdev, FOREGROUND_COLOR | ulHwMix);
    IO_PIX_CNTL(ppdev, ALL_ONES);

    fl = 0;

// Look after styling initialization:

    if (pla->fl & LA_ALTERNATE)
    {
        ls.cStyle      = 1;
        ls.spTotal     = 1;
        ls.spTotal2    = 2;
        ls.spRemaining = 1;
        ls.aspRtoL     = &gaspAlternateStyle[0];
        ls.aspLtoR     = &gaspAlternateStyle[0];
        ls.spNext      = HIWORD(pla->elStyleState.l);
        ls.xyDensity   = 1;
        fl            |= FL_ARBITRARYSTYLED;
        ls.ulStartMask = 0L;
    }
    else if (pla->pstyle != (FLOAT_LONG*) NULL)
    {
        PFLOAT_LONG pstyle;
        STYLEPOS*   pspDown;
        STYLEPOS*   pspUp;

        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);

        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];

        while (pspDown >= &ls.aspRtoL[0])
        {
            *pspDown = pstyle->l * STYLE_DENSITY;
            *pspUp   = *pspDown;

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

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

// Set up to enumerate the path:

#if defined(_X86_)

// x86 ASM bLines supports DC_RECT clipping:

    if (pco->iDComplexity != DC_COMPLEX)

#else

// Non-x86 ASM bLines don't support DC_RECT clipping:

    if (pco->iDComplexity == DC_TRIVIAL)

#endif

    {
        PATHDATA  pd;
        RECTL*    prclClip = (RECTL*) NULL;
        BOOL      bMore;
        ULONG     cptfx;
        POINTFIX  ptfxStartFigure;
        POINTFIX  ptfxLast;
        POINTFIX* pptfxFirst;
        POINTFIX* pptfxBuf;

#if defined(_X86_)

        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;
        }

#endif // _X86_

        pd.flags = 0;

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

            cptfx = pd.count;
            if (cptfx == 0)
            {
                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;

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

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

            if (pd.flags & PD_CLOSEFIGURE)
            {
                if (!bLines(ppdev,
                            &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;

        // 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(ppdev,
                            &cl.cl.ptfxA,
                            &cl.cl.ptfxB,
                            &cl.cl.arun[0],
                            cl.cl.c,
                            &ls,
                            (RECTL*) NULL,
                            apfn,
                            fl))
                    return(FALSE);
            }
        } while (bMore);
    }

    return(TRUE);
}
Ejemplo n.º 2
0
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;
    PPDEV     ppdev = (PPDEV) pso->dhsurf;

    UNREFERENCED_PARAMETER(pxo);
    UNREFERENCED_PARAMETER(pptlBrushOrg);

// Fast lines can't handle trivial clipping, ROPs other than R2_COPYPEN, or
// styles:

    mix &= 0xf;
    if ((mix == 0x0d) &&
        (pco->iDComplexity == DC_TRIVIAL) &&
        (pla->pstyle == NULL) && !(pla->fl & LA_ALTERNATE))
    {
        vFastLine(ppdev, ppo, ppdev->lNextScan,
                  (pbo->iSolidColor << 8) | (pbo->iSolidColor & 0xff));
        return(TRUE);
    }

    fl = 0;

// Look after styling initialization:

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

        ls.bStartIsGap  = 0;                        // First pel is a dash
        ls.cStyle       = 1;                        // Size of style array
        ls.spTotal      = 1;                        // Sum of style array
        ls.spTotal2     = 2;                        // Twice the sum
        ls.aspRtoL      = &gaspAlternateStyle[0];   // Right-to-left array
        ls.aspLtoR      = &gaspAlternateStyle[0];   // Left-to-right array
        ls.spNext       = HIWORD(pla->elStyleState.l) & 1;
                                                    // Light first pixel if
                                                    //   a multiple of 2
        ls.xyDensity    = 1;                        // Each 'dot' is one
                                                    //   pixel long
        fl             |= FL_ARBITRARYSTYLED;
    }
    else if (pla->pstyle != (FLOAT_LONG*) NULL)
    {
        FLOAT_LONG* pstyle;
        STYLEPOS*   pspDown;
        STYLEPOS*   pspUp;

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

    // Compute length of style array:

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

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

    // The style array is given in 'style' units.  Since we're going to
    // assign each unit to be STYLE_DENSITY (3) pixels long, multiply:

        ls.spTotal *= STYLE_DENSITY;
        ls.spTotal2 = 2 * ls.spTotal;

    // Compute starting style position (this is guaranteed not to overflow).
    // Note that since the array repeats infinitely, this number might
    // actually be more than ls.spTotal2, but we take care of that later
    // in our code:

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

        fl            |= FL_ARBITRARYSTYLED;
        ls.cStyle      = pla->cstyle;
        ls.aspRtoL     = aspRtoL;   // Style array in right-to-left order
        ls.aspLtoR     = aspLtoR;   // Style array in left-to-right order

    // ulStartMask determines if the first entry in the style array is for
    // a dash or a gap:

        ls.bStartIsGap = (pla->fl & LA_STARTGAP) ? -1L : 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])
        {
            ASSERTVGA(pstyle->l > 0 && pstyle->l <= STYLE_MAX_VALUE,
                   "Illegal style array value");

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

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

    {
    // All ROPs are handled in a single pass:

        ULONG achColor[4];
        LONG  iIndex;
        ULONG iColor = (pbo->iSolidColor & 0xff);

        achColor[AND_ZERO]   =  0;
        achColor[AND_PEN]    =  pbo->iSolidColor;
        achColor[AND_NOTPEN] = ~pbo->iSolidColor;
        achColor[AND_ONE]    =  (ULONG) -1L;

        iIndex = gaiLineMix[mix];

    // We have special strip drawers for set-style ROPs (where we don't
    // have to read video memory):

        if ((iIndex & 0xff) == AND_ZERO)
            fl |= FL_SET;

    // Put the AND index in the low byte, and the XOR index in the next:

        *((BYTE*) &ls.chAndXor)     = (BYTE) achColor[iIndex & 0xff];
        *((BYTE*) &ls.chAndXor + 1) = (BYTE) achColor[iIndex >> MIX_XOR_OFFSET];
    }

    apfn = &gapfnStrip[4 * ((fl & FL_STRIP_ARRAY_MASK) >> FL_STRIP_ARRAY_SHIFT)];

// 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;
        }

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

            cptfx = pd.count;
            if (cptfx == 0)
            {
                ASSERTVGA(!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(ppdev,
                            pptfxFirst,
                            pptfxBuf,
                            (RUN*) NULL,
                            cptfx,
                            &ls,
                            prclClip,
                            apfn,
                            fl))
                    return(FALSE);
            }

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

            if (pd.flags & PD_CLOSEFIGURE)
            {
                if (!bLines(ppdev,
                            &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;

            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(ppdev,
                            &cl.cl.ptfxA,
                            &cl.cl.ptfxB,
                            &cl.cl.arun[0],
                            cl.cl.c,
                            &ls,
                            (RECTL*) NULL,
                            apfn,
                            fl))
                    return(FALSE);
            }
        } while (bMore);
    }

    return(TRUE);
}
Ejemplo n.º 3
0
BOOL
DoStrokePathByEnumingClipLines(
    PPDEV       pPDev,
    SURFOBJ     *pso,
    CLIPOBJ     *pco,
    PATHOBJ     *ppo,
    PPOINTL     pptlBrushOrg,
    BRUSHOBJ    *pbo,
    ROP4        rop4,
    LINEATTRS   *plineattrs
    )

/*++

Routine Description:

    Strokes a path through a complex clipping region by utilizing the
    engine helper functions. This is done because there is no way to
    fail a DrvStrokePath and have it come back in any simpler format by
    the NT graphics engine. In general, we can fail DrvXXX calls and the
    NT graphic engine will simply the object to draw, then call back into
    the driver. Stroking a path however cannot be simplified any more, so
    the best we can hope for is having the PATHOBJ converted to straight
    line segments (removing BEZIERS if present). We then must stroke the
    path ourselves, using the provided EngXXX helpers.
    Since helper functions exist that allow us to to enumerate the
    portions of a path as CLIPLINE segments that fall within the
    clipping region, we do that here, thus stroking the segments that lie
    inside of the passed CLIPOBJ.


Arguments:

    pPDev            Pointer to the current PDEV

    pso              SURFOBJ to write to

    pco              CLIPOBJ to use when enuming paths

    ppo              PATHOBJ to stroke through clip path

    pptlBrushOrg     BRUSH origin

    pbo              BRUSH to stroke with

    rop4             ROP4 to use

    plineattrs       LINEATTRS structure that describes the styling for the line



Return Value:

    TRUE if sucessful FALSE if failed, If the path we are asked to stroke
          contains BEZIERS, this function will fail in order to allow the
          Engine to break the path down to line segments.

Author:


    2/01/94  JB

Revision History:


--*/

{
    PLOT_CLIPLINE   PlotClipLine;
    CLIPLINE        *pCurClipLine;
    RUN             *pCurRun;
    POINTFIX        ptsfx[2];
    POINTL          ptlCur;
    FIX             iStartInFX;
    FIX             iStopInFX;
    LONG            dx;
    LONG            dy;
    LONG            i;
    BOOL            bMore;
    BOOL            bXordered;
    BOOL            bFlipX;
    BOOL            bFlipY;


    //
    // First check for Beziers and if we have them fail the call since we
    // want straight line segments to stroke, with the appropriate style
    //

    if (ppo->fl & PO_BEZIERS) {

        PLOTDBG(DBG_STROKECLIPLINES,
                ("DoStrokePathByEnumingClipLines:Path had BEZ returning FALSE"));
        return(FALSE);
    }

    PLOTDBG(DBG_STROKECLIPLINES,
            ("DoStrokeByEnumingClipLines: NO CLIPOBJ %p",
                  (pco != NULL) ,
                  (LONG_PTR)pco));

    PLOTDBG(DBG_STROKECLIPLINES, 
            ("DoStrokeByEnumingClipLines: CLIPOBJ is TRIVIAL (%lx)",
                  (pco->iDComplexity != DC_TRIVIAL) ,
                  (LONG)pco->iDComplexity ));

    //
    // Send out the line attributes , so the residue will be calculated
    // correctly
    //

    DoSetupOfStrokeAttributes(pPDev, pptlBrushOrg, pbo, rop4, NULL);

    //
    // Initiate enumeration of the CLIPLINES by calling the Engine helper
    //

    PATHOBJ_vEnumStartClipLines(ppo, pco, pso, plineattrs);

    //
    // Start a loop to enum through all the available CLIPLINE structures
    //

    pCurClipLine = (CLIPLINE *)&PlotClipLine;

    do {

        //
        // Get the first batch of CLIPLINE structures then go to work on them
        //

        bMore = PATHOBJ_bEnumClipLines(ppo, sizeof(PlotClipLine), pCurClipLine);

        //
        // Calculate dx and dy in order to determine if the line is Xordered or
        // Yordered this is needed because of the way the engine passes us RUNS
        // if dx > dy then the line is said to be Xordered and thus any given
        // RUN iStart and iStop values is a projection on the x axis. Given this
        // informatino we can calculate the adjoining Y coordinate and draw the
        // line appropriately.
        //

        dx = pCurClipLine->ptfxB.x - pCurClipLine->ptfxA.x;
        dy = pCurClipLine->ptfxB.y - pCurClipLine->ptfxA.y;



        if ( bFlipX = (dx < 0 )) {

            dx = -dx;
        }

        if ( bFlipY = (dy < 0 )) {

            dy = -dy;
        }


        //
        // Now calculate if the line is x ordered or y ordered
        //

        bXordered = (dx >= dy);

        PLOTDBG(DBG_STROKECLIPLINES,
                   ("DoStrokePathByEnumingClipLines:Compute ClipLine runs=%u, xordered %d",
                   pCurClipLine->c, bXordered ));

        //
        // Enum through all the given RUNS drawing with the pen down between any
        // iStart and iStop value in each RUN
        //

        for (i = 0, pCurRun = &(pCurClipLine->arun[0]);
             i < (LONG)pCurClipLine->c;
             i++, pCurRun++) {


            //
            // The value of iStart and iStop are always positive!! so
            // we must handle it ourselves, so the correct thing happens
            //

            iStartInFX = LTOFX(pCurRun->iStart);
            iStopInFX  = LTOFX(pCurRun->iStop);


            if (bFlipX ) {

                ptsfx[0].x = -iStartInFX;
                ptsfx[1].x = -iStopInFX;

            } else {

                ptsfx[0].x = iStartInFX;
                ptsfx[1].x = iStopInFX;
            }

            if (bFlipY ) {

                ptsfx[0].y = -iStartInFX;
                ptsfx[1].y = -iStopInFX;

            } else {

                ptsfx[0].y = iStartInFX;
                ptsfx[1].y = iStopInFX;
            }


            //
            // We must output the correct line attributes structure with the
            // correct calculated residue in order for this to work correctly
            //

            HandleLineAttributes(pPDev,
                                 plineattrs,
                                 &pCurClipLine->lStyleState,
                                 pCurRun->iStart);



            //
            // The calculations for the opposing coordinate varies based on the
            // ordering of the line. If the line is Xordered we calculate the
            // Y value, if itsYordered we calculate the X value. We do this
            // in order to determine the correct target coordinate. Since the
            // RUN is given to us as START and STOP, we must manually determine
            // what coordinate this represents inside the device coordinate
            // space. If the RUN is xordered, the x-coordinate is correct, and
            // the y-coordinate must be projected based on the ratio.
            //

            if (bXordered) {

                ptsfx[0].x +=  pCurClipLine->ptfxA.x;
                ptsfx[0].y =   MulDiv( ptsfx[0].y, dy, dx) +
                                                        pCurClipLine->ptfxA.y;
                ptsfx[1].x +=  pCurClipLine->ptfxA.x;
                ptsfx[1].y =   MulDiv( ptsfx[1].y, dy, dx) +
                                                        pCurClipLine->ptfxA.y;

            } else {

                ptsfx[0].x =   MulDiv(ptsfx[0].x, dx, dy) +
                                                        pCurClipLine->ptfxA.x;
                ptsfx[0].y +=  pCurClipLine->ptfxA.y;
                ptsfx[1].x =   MulDiv(ptsfx[1].x, dx, dy) +
                                                        pCurClipLine->ptfxA.x;
                ptsfx[1].y +=  pCurClipLine->ptfxA.y;
            }


            //
            // Do PE with pen up first, in order to move to the starting
            // position.
            //

            OutputString(pPDev, "PE<");

            if (!i) {

                //
                // If we are at first point then output that now.
                //

                ptlCur.x =
                ptlCur.y = 0;

                OutputString(pPDev, "=");
            }


            //
            // Stroke the segment with the pen down.
            //

            OutputXYParams(pPDev,
                           (PPOINTL)ptsfx,
                           (PPOINTL)NULL,
                           (PPOINTL)&ptlCur,
                           (UINT)2,
                           (UINT)1,
                           'F');

            OutputString(pPDev, ";");
        }

    } while (bMore);  // While we need to enum again..

    return(TRUE);
}