Beispiel #1
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);
}
Beispiel #2
0
void vrdpDrvStrokePath(SURFOBJ *pso, PATHOBJ *ppo, CLIPOBJ *pco, XFORMOBJ *pxo,
                       BRUSHOBJ  *pbo, POINTL *pptlBrushOrg, LINEATTRS *plineattrs, MIX mix)
{
    PVBOXDISPDEV pDev = (PVBOXDISPDEV)pso->dhpdev;

    /*
     * StrokePath operation is supported by RDP_ORDER_POLYGON/POLYLINE/ELLIPSE.
     */
    VRDPCLIPRECTS clipRects;
    int clipResult;
    RECTFX rcfxBounds;
    RECTL rclBoundsOrdered;

    LOGF(("pso = %p, ppo = %p, pco = %p, pxo = %p, pbo = %p, pptlBrushOrg = %p, plineattrs = %p, mix = 0x%08X",
           pso, ppo, pco, pxo, pbo, pptlBrushOrg, plineattrs, mix));
    LOGF(("ppo: fl = 0x%08X, cCurves = %d", ppo->fl, ppo->cCurves));

    PATHOBJ_vGetBounds(ppo, &rcfxBounds);

    rclBoundsOrdered.left   = FXTOLFLOOR(rcfxBounds.xLeft);
    rclBoundsOrdered.right  = FXTOLCEILING(rcfxBounds.xRight);
    rclBoundsOrdered.top    = FXTOLFLOOR(rcfxBounds.yTop);
    rclBoundsOrdered.bottom = FXTOLCEILING(rcfxBounds.yBottom);

    vrdpOrderRect(&rclBoundsOrdered);

    LOG(("ppo: bounds %x-%x, %x-%x, %d-%d %d-%d",
         rcfxBounds.xLeft, rcfxBounds.xRight, rcfxBounds.yTop, rcfxBounds.yBottom,
         rclBoundsOrdered.left, rclBoundsOrdered.right, rclBoundsOrdered.top, rclBoundsOrdered.bottom));

    clipResult = vrdpGetIntersectingClipRects(&clipRects, pso, &rclBoundsOrdered, pco, NULL);

    if (clipResult == VRDP_CLIP_NO_INTERSECTION)
    {
        /* Do nothing. The operation does not affect anything. */
        LOG(("VRDP_CLIP_NO_INTERSECTION!!!"));
        dumpPCO (&rclBoundsOrdered, pco);
    }
    else if (clipResult == VRDP_CLIP_TOO_MANY_RECTS)
    {
        /* A very complex clip. Better to emulate it. */
        LOG(("VRDP_CLIP_TOO_MANY_RECTS!!!"));
        dumpPCO (&rclBoundsOrdered, pco);

        vrdpReportDirtyRects(pDev, &clipRects);
    }
    else if (pbo->iSolidColor == 0xFFFFFFFF)
    {
        /* Not solid brushes are not supported. */
        vrdpReportDirtyRects(pDev, &clipRects);
    }
    else if (ppo->fl & PO_ELLIPSE)
    {
        if (VBoxVBVAOrderSupported(&pDev->vbvaCtx, VRDE_ORDER_ELLIPSE))
        {
            VRDEORDERELLIPSE order;

            order.pt1.x = (int16_t)FXTOLROUND(rcfxBounds.xLeft   + 4);
            order.pt1.y = (int16_t)FXTOLROUND(rcfxBounds.yTop    + 4);
            order.pt2.x = (int16_t)FXTOLROUND(rcfxBounds.xRight  - 4);
            order.pt2.y = (int16_t)FXTOLROUND(rcfxBounds.yBottom - 4);

            order.mix = (uint8_t)(mix & 0x1F);
            order.fillMode = 0;
            order.rgb = vrdpColor2RGB(pso, pbo->iSolidColor);

            vrdpReportOrderGeneric(pDev, &clipRects, &order, sizeof (order), VRDE_ORDER_ELLIPSE);
        }
        else
        {
            WARN(("ELLIPSE not supported"));
            vrdpReportDirtyRects (pDev, &clipRects);
        }
    }
    else if (   (ppo->fl & PO_BEZIERS) == 0
             && (plineattrs->fl & LA_GEOMETRIC) == 0
             && plineattrs->pstyle == NULL)
    {
        unsigned i;
        PATHDATA pd;
        BOOL bMore;
        VRDEORDERPOLYLINE order;
        VRDEORDERPOINT ptStart;
        VRDEORDERBOUNDS bounds;

        order.rgb = vrdpColor2RGB(pso, pbo->iSolidColor);
        order.mix = (uint8_t)(mix & 0x1F);

        PATHOBJ_vEnumStart(ppo);

        order.points.c = 0;

        do {
            POINTFIX *pptfx;
            VRDEORDERPOINT pt;

            bMore = PATHOBJ_bEnum (ppo, &pd);

            LOG(("pd: flags = 0x%08X, count = %d", pd.flags, pd.count));

            pptfx = &pd.pptfx[0];

            if (pd.flags & PD_BEGINSUBPATH)
            {
                /* Setup first point. Start a new order. */
                LOG(("BEGINSUBPATH"));

                Assert(order.points.c == 0);

                vrdpPointFX2Point(pptfx, &ptStart);
                order.ptStart = ptStart;
                pt = ptStart;

                bounds.pt1 = bounds.pt2 = ptStart;

                pptfx++;
                i = 1;
            }
            else
            {
                LOG(("Continue order"));

                i = 0;
            }

            for (; i < pd.count; i++, pptfx++)
            {
                LOG(("pd: %2d: %x,%x %d,%d",
                     i, pptfx->x, pptfx->y, FXTOLROUND(pptfx->x), FXTOLROUND(pptfx->y)));

                vrdpPointFX2Point     (pptfx, &pt);
                vrdpPolyPointsAdd     (&order.points, &pt);
                vrdpExtendOrderBounds (&bounds, &pt);

                if (order.points.c == RT_ELEMENTS(order.points.a))
                {
                    /* Flush the order and start a new order. */
                    LOG(("Report order, points overflow."));

                    vrdpReportOrderGenericBounds(pDev, &clipRects, &bounds, &order, sizeof (order), VRDE_ORDER_POLYLINE);

                    order.points.c = 0;
                    order.ptStart = pt;
                    bounds.pt1 = bounds.pt2 = pt;
                }
            }

            if (pd.flags & PD_CLOSEFIGURE)
            {
                /* Encode the start point as the end point. */
                LOG(("Report order, CLOSEFIGURE"));

                if (   ptStart.x != pt.x
                    || ptStart.y != pt.y)
                {
                    Assert(order.points.c < RT_ELEMENTS(order.points.a));

                    vrdpPolyPointsAdd     (&order.points, &ptStart);
                    vrdpExtendOrderBounds (&bounds, &ptStart);
                }
            }

            if (pd.flags & PD_ENDSUBPATH)
            {
                /* Finish the order. */
                LOG(("Report order, ENDSUBPATH"));

                if (order.points.c > 0)
                {
                    vrdpReportOrderGenericBounds(pDev, &clipRects, &bounds, &order, sizeof (order), VRDE_ORDER_POLYLINE);
                }

                order.points.c = 0;
            }
        } while (bMore);
    }
    else
    {
        /* Not supported. */
        WARN(("not supported: ppo->fl = %08X, plineattrs->fl = %08X, plineattrs->pstyle = %08X",
              ppo->fl, plineattrs->fl, plineattrs->pstyle));

        vrdpReportDirtyRects(pDev, &clipRects);
    }

    return;
}
Beispiel #3
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);
}