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