|
|
/******************************Module*Header*******************************\
* Module Name: fillddi.cxx * * Contains filling simulations code and help functions. * * Created: 04-Apr-1991 17:30:35 * Author: Wendy Wu [wendywu] * * Copyright (c) 1990-1999 Microsoft Corporation \**************************************************************************/
#include "precomp.hxx"
/******************************Member*Function*****************************\
* EngFillPath * * This routine first converts the given pathobj to rgnmemobj then * calls EngPaint to fill. * * History: * 07-Mar-1992 -by- Donald Sidoroff [donalds] * Rewrote to call (Drv/Eng)Paint * * 13-Feb-1991 -by- Wendy Wu [wendywu] * Wrote it. \**************************************************************************/
BOOL EngFillPath( SURFOBJ *pso, PATHOBJ *ppo, CLIPOBJ *pco, BRUSHOBJ *pbo, PPOINTL pptlBrushOrg, MIX mix, FLONG flOptions ) { GDIFunctionID(EngFillPath); ASSERTGDI(pso != (SURFOBJ *) NULL, "pso is NULL\n"); ASSERTGDI(ppo != (PATHOBJ *) NULL, "ppo is NULL\n"); ASSERTGDI(pco != (CLIPOBJ *) NULL, "pco is NULL\n");
PSURFACE pSurf = SURFOBJ_TO_SURFACE(pso); PDEVOBJ po(pSurf->hdev()); SUSPENDWATCH sw(po);
ASSERTGDI(pco->iMode == TC_RECTANGLES, "Invalid clip object iMode");
// Check if we have to flatten any Beziers:
if (ppo->fl & PO_BEZIERS) if (!((EPATHOBJ*) ppo)->bFlatten()) return(FALSE);
// Before we touch any bits, make sure the device is happy about it.
po.vSync(pso,&pco->rclBounds,0);
// check if we can try the fast fill.
if (!( pSurf->flags() & HOOK_PAINT) && (pco->iDComplexity != DC_COMPLEX)) { PRECTL prclClip = NULL;
if ((pco->iDComplexity == DC_RECT) || (pco->fjOptions & OC_BANK_CLIP)) { RECTFX rcfx = ((EPATHOBJ*)ppo)->rcfxBoundBox();
// check the bound box, maybe it really is unclipped
if ((pco->rclBounds.left > (rcfx.xLeft >> 4)) || (pco->rclBounds.right < ((rcfx.xRight + 15) >> 4)) || (pco->rclBounds.top > (rcfx.yTop >> 4)) || (pco->rclBounds.bottom < ((rcfx.yBottom + 15) >> 4))) { prclClip = &pco->rclBounds; } }
// -1 - couldn't handle, 0 error, 1 success
LONG lRes = EngFastFill(pso,ppo,prclClip,pbo,pptlBrushOrg,mix,flOptions); if (lRes >= 0) return(lRes); }
// Convert path to region.
RECTL Bounds,*pBounds;
if( pco->iDComplexity != DC_TRIVIAL ) { Bounds.top = (pco->rclBounds.top) << 4; Bounds.bottom = (pco->rclBounds.bottom) << 4; pBounds = &Bounds; } else { pBounds = NULL; }
RGNMEMOBJTMP rmo(*((EPATHOBJ *)ppo), flOptions, pBounds);
if (!rmo.bValid()) { SAVE_ERROR_CODE(ERROR_NOT_ENOUGH_MEMORY); return(FALSE); }
if (rmo.iComplexity() == NULLREGION) return(TRUE);
// CLIPOBJ_bEnum will do the clipping if clipping is not complex.
ERECTL erclClip(pco->rclBounds);
if (pco->iDComplexity == DC_TRIVIAL) { ECLIPOBJ ecoPath(rmo.prgnGet(), erclClip); if (ecoPath.erclExclude().bEmpty()) return(TRUE);
if (ecoPath.iDComplexity == DC_TRIVIAL) ecoPath.iDComplexity = DC_RECT;
// Inc the target surface uniqueness
INC_SURF_UNIQ(pSurf);
BOOL bRet; sw.Resume(); bRet = EngPaint( pso, // Destination surface.
&ecoPath, // Clip object.
pbo, // Realized brush.
pptlBrushOrg, // Brush origin.
mix); // Mix mode.
return(bRet); }
// Create a RGNMEMOBJ for bMerge since it will trash the target.
RGNMEMOBJTMP rmoTrg;
if (!rmoTrg.bValid()) { SAVE_ERROR_CODE(ERROR_NOT_ENOUGH_MEMORY); return(FALSE); }
// Merge the region we just constructed with the clip region.
if (!rmoTrg.bMerge(rmo, *((ECLIPOBJ *)pco), gafjRgnOp[RGN_AND])) return(FALSE);
ERECTL ercl; rmoTrg.vGet_rcl(&ercl);
ercl *= ((ECLIPOBJ *)pco)->erclExclude();
ECLIPOBJ co(rmoTrg.prgnGet(), ercl);
if (co.erclExclude().bEmpty()) return(TRUE);
if (co.iDComplexity == DC_TRIVIAL) co.iDComplexity = DC_RECT;
// Inc the target surface uniqueness
INC_SURF_UNIQ(pSurf); sw.Resume();
sw.Resume(); return(EngPaint( pso, // Destination surface.
&co, // Clip object.
pbo, // Realized brush.
pptlBrushOrg, // Brush origin.
mix)); // Mix mode.
}
/******************************Member*Function*****************************\
* EngStrokeAndFillPath * * Engine simulation for stroking and filling the given path. * * History: * 06-Apr-1992 -by- J. Andrew Goossen [andrewgo] * Re-wrote it to do region subtraction. * * 02-Oct-1991 -by- Wendy Wu [wendywu] * Wrote it. \**************************************************************************/
BOOL EngStrokeAndFillPath( SURFOBJ *pso, PATHOBJ *ppo, CLIPOBJ *pco, XFORMOBJ *pxo, BRUSHOBJ *pboStroke, LINEATTRS *pla, BRUSHOBJ *pboFill, POINTL *pptlBrushOrg, MIX mix, FLONG flOptions) { BOOL bRet = FALSE;
PSURFACE pSurf = SURFOBJ_TO_SURFACE(pso);
MIX mixFill, mixStroke;
mixFill = mixStroke = mix;
if (!((EBRUSHOBJ *)pboFill)->bIsMasking()) { mixFill = (mix & 0xff) | ((mix & 0xff) << 8); }
if (!((EBRUSHOBJ *)pboStroke)->bIsMasking()) { mixStroke = (mix & 0xff) | ((mix & 0xff) << 8); }
ERECTL ercl;
// If we're not doing a wide-line, or if we're doing a wide-line and
// the mix is overwrite so we don't care about re-lighting pixels,
// make two calls out of it:
if (!(pla->fl & LA_GEOMETRIC) || ((mix & 0xFF) == R2_COPYPEN)) { bRet = EngFillPath(pso, ppo, pco, pboFill, pptlBrushOrg, mixFill, flOptions) && EngStrokePath(pso, ppo, pco, pxo, pboStroke, pptlBrushOrg, pla, mixStroke); return(bRet); }
// Okay, we have a wideline call with a weird mix mode. Because part
// of the wide-line overlaps part of the fill, we will convert both to
// regions, and subtract them so that they won't overlap.
// Convert the widened outline to a region. We have to widen the path
// before flattening it (for the fill) because the widener will produce
// better looking wide curves that way:
PATHMEMOBJ pmoStroke;
if (!pmoStroke.bValid() || !pmoStroke.bComputeWidenedBounds(*(EPATHOBJ*) ppo, pxo, pla) || !pmoStroke.bWiden(*(EPATHOBJ*) ppo, pxo, pla)) { SAVE_ERROR_CODE(ERROR_NOT_ENOUGH_MEMORY); return(bRet); }
// First flatten any curves and then convert the interior to a region:
if (ppo->fl & PO_BEZIERS) { if (!((EPATHOBJ*) ppo)->bFlatten()) { return(bRet); } }
// Create the regions:
RGNMEMOBJTMP rmoStroke(pmoStroke, WINDING); RGNMEMOBJTMP rmoFill(*((EPATHOBJ *)ppo), flOptions); RGNMEMOBJTMP rmoNewFill;
if (rmoFill.bValid() && rmoStroke.bValid() && rmoNewFill.bValid() && rmoNewFill.bMerge(rmoFill, rmoStroke, gafjRgnOp[RGN_DIFF])) { // Create a RGNMEMOBJ for bMerge since it will trash the target.
RGNMEMOBJTMP rmoTrg;
if (rmoTrg.bValid()) { PDEVOBJ pdo(pSurf->hdev());
// Paint the stroked outline:
if (rmoStroke.iComplexity() != NULLREGION) { // Merge the outline region with the clip region:
if (!rmoTrg.bMerge(rmoStroke, *((ECLIPOBJ *)pco), gafjRgnOp[RGN_AND])) { bRet = FALSE; } else { rmoTrg.vGet_rcl(&ercl); ECLIPOBJ co(rmoTrg.prgnGet(), ercl);
if (co.erclExclude().bEmpty()) { bRet = TRUE; } else { INC_SURF_UNIQ(pSurf);
bRet = EngPaint( pso, &co, pboStroke, pptlBrushOrg, mixStroke);
} } }
// Paint the filled interior:
if ((bRet == TRUE) && rmoNewFill.iComplexity() != NULLREGION) { // Merge the inside region with the clip region.
if (!rmoTrg.bMerge(rmoNewFill, *((ECLIPOBJ *)pco), gafjRgnOp[RGN_AND])) { bRet = FALSE; } else { rmoTrg.vGet_rcl(&ercl); ECLIPOBJ co(rmoTrg.prgnGet(), ercl);
if (co.erclExclude().bEmpty()) { bRet = TRUE; } else { INC_SURF_UNIQ(pSurf);
bRet = EngPaint(pso, &co, pboFill, pptlBrushOrg, mixFill); } } } } }
return(bRet); }
|