/******************************Module*Header*******************************\ * Module Name: pathclip.cxx * * This module handles the reading of the path for the line-clipping * component (which resides mostly in clipline.cxx). * * Created: 02-Apr-1991 08:45:30 * Author: Eric Kutter [erick] * * Copyright (c) 1991-1999 Microsoft Corporation \**************************************************************************/ #include "precomp.hxx" /******************************Public*Routine******************************\ * PATHOBJ_vEnumStartClipLines * * Engine helper function. * * History: * 04-Apr-1991 -by- Eric Kutter [erick] * Wrote it. \**************************************************************************/ VOID PATHOBJ_vEnumStartClipLines( PATHOBJ *ppo, CLIPOBJ *pco, SURFOBJ *pso, PLINEATTRS pla) { PSURFACE pSurf = SURFOBJ_TO_SURFACE(pso); ((ECLIPOBJ *)pco)->vEnumPathStart(ppo, pSurf, pla); } /******************************Public*Routine******************************\ * PATHOBJ_bEnumClipLines * * Engine helper function. * * History: * 04-Apr-1991 -by- Eric Kutter [erick] * Wrote it. \**************************************************************************/ BOOL PATHOBJ_bEnumClipLines( PATHOBJ *ppo, ULONG cj, PCLIPLINE pcl) { ECLIPOBJ *pco = (ECLIPOBJ *)((EPATHOBJ *)ppo)->pco; return(pco->bEnumPath(ppo,cj,pcl)); } /******************************Member*Function*****************************\ * XCLIPOBJ::vEnumPathStart * * History: * 24-Feb-1992 -by- J. Andrew Goossen [andrewgo] * Added styling support. * * 04-Apr-1991 -by- Eric Kutter [erick] * Wrote it. \**************************************************************************/ VOID XCLIPOBJ::vEnumPathStart(PATHOBJ *ppo_, SURFACE *pSurf, PLINEATTRS pla) { EPATHOBJ *ppo = (EPATHOBJ *)ppo_; pcle = ppo->pcleGet(); ppo->vEnumStart(); ppo->pco = (CLIPOBJ *)this; pcle->fl = CLO_LINEDONE; // need a new line segment pcle->cPoints = 0; // spTotal2 will be non-zero when we're doing styling: pcle->spTotal2 = 0; pcle->plStyleState = &pla->elStyleState.l; pcle->xStep = 1; pcle->yStep = 1; pcle->xyDensity = 1; if (pla->fl & LA_ALTERNATE) { // Alternate style is special and has every second pixel off, so // we pretend a style unit is a single pixel long, and that we // have the style array {1}: pcle->spTotal2 = 2; pcle->spStyleEnd = HIWORD(pla->elStyleState.l) & 1; } else if (pla->pstyle != (PFLOAT_LONG) NULL) { if (pSurf->hdev() == 0) { WARNING("Driver didn't call EngAssociateSurface before calling\n"); WARNING("EngStrokePath or vEnumPathStart, so styles may be wrong\n"); pcle->xyDensity = 3; // Supply a default } else { PDEVOBJ po(pSurf->hdev()); pcle->xStep = po.xStyleStep(); pcle->yStep = po.yStyleStep(); pcle->xyDensity = po.denStyleStep(); } // Get ready for styling: PFLOAT_LONG pstyle = pla->pstyle + pla->cstyle; while (pstyle > pla->pstyle) { pstyle--; pcle->spTotal2 += pstyle->l; } ASSERTGDI((pcle->spTotal2 & ~0x7fffL) == 0, "Style array too long"); pcle->spTotal2 <<= 1; pcle->spTotal2 *= pcle->xyDensity; // Construct our scaled style state, remembering that a driver could // have left the style state in a funky way: pcle->spStyleEnd = HIWORD(pla->elStyleState.l) * pcle->xyDensity + LOWORD(pla->elStyleState.l); pcle->spStyleEnd %= (ULONG) pcle->spTotal2; if (pcle->spStyleEnd < 0) { WARNING("GDISRV vEnumPathStart: style state < 0\n"); pcle->spStyleEnd = 0; } } // get the first line. We don't care about flOld because we // don't care about last pel exclusion here. FLONG flOld; bGetLine(ppo,&flOld); } /******************************Member*Function*****************************\ * BOOL XCLIPOBJ::bEnumPath * * bEnumPath fills the pcl data structure with a line and runs that * specify uncliped parts of the line. If there are too many runs to * fit in the supplied structure, the next call to this function will * return the next set of runs. * * This routine assumes that the line to be clipped is already set in * the XCLIPOBJ which initialy is done through vEnumStartPath. After * that, this routine will always complete with the next line setup. * * returns * TRUE - there are more runs to enumerate * FALSE - this is the last set of runs in the path * * History: * * 21-Feb-1992 -by- J. Andrew Goossen [andrewgo] * Made lines exclusive of ends. * * 04-Apr-1991 -by- Eric Kutter [erick] * Wrote it. \**************************************************************************/ BOOL XCLIPOBJ::bEnumPath( PATHOBJ *ppo_, ULONG cj, PCLIPLINE pcl) { pcl->c = 0; // See if we're simply done the path: if (bEnumDone()) return(FALSE); EPATHOBJ *ppo = (EPATHOBJ *) ppo_; BOOL bMore; do { // assume next line already setup. // get the run's for the current line. If we have all the runs, do // last pel exclusion. If we don't have all of the runs, we know // there is at least one unclipped pel after the current set of runs. bMore = bEnumLine(cj,pcl); if (!bMore) { // save information about current line FLONG flOld = pcle->fl; ASSERTGDI(pcle->dda.lX1 >= pcle->dda.lX0, "irunOld < 0"); // get the next non-zero length line (bGetLine is FALSE if there aren't // any more lines in the path): bGetLine(ppo,&flOld); } } while ((pcl->c == 0) && !bEnumDone()); // if we made it to here with no runs, we must be done. if (bEnumDone() && bStyling()) { // We're all done, so update style state in LINEATTRS: *pcle->plStyleState = lGetStyleState(pcle->spStyleEnd); } return(!bEnumDone()); } /******************************Public*Routine******************************\ * XCLIPOBJ::bGetLine * * Fill ppo with the next line segment in the path. This may be a closing * segment of the current sub-path. * * It may be necessary to ask the path for more points. * * returns * TRUE - if there were more line segments * FALSE - if no more line segments. * * History: * 16-Oct-1991 -by- Eric Kutter [erick] * Wrote it. \**************************************************************************/ BOOL XCLIPOBJ::bGetLine(EPATHOBJ *ppo, FLONG *pflOld) { DONTUSE(pflOld); FLONG fl; FLONG flBeginSub = 0; // This for(;;) is for eating zero-length lines for (;;) { if (bEnumDone()) return(FALSE); // if we still have more points in the current set if (pcle->cPoints > 1) { pcle->ptfx0 = *pcle->pptfx1; ++pcle->pptfx1; --pcle->cPoints; if (bEnumStartLine((PD_CLOSEFIGURE & pcle->fl) | flBeginSub)) return(TRUE); } // otherwise, if we need to close the figure else if (bCloseFigure()) { pcle->ptfx0 = *pcle->pptfx1; pcle->pptfx1 = &pcle->ptfxStartSub; // bEnumStartLine will turn off PD_CLOSFIGURE and turn on CLO_CLOSING: if (!bEnumStartLine(CLO_CLOSING) || flBeginSub) continue; return(TRUE); } // otherwise, lets get some more points else { if (!bGetMorePoints(ppo,&fl)) { return(FALSE); } if (bEnumStartLine(fl | flBeginSub)) return(TRUE); // Okay, the first line in the subpath was zero-length. So remember // that we're really still at the start of a subpath, and get the // next line: // NOTE: We have to make sure we pass on the RESETSTYLE flag too! flBeginSub |= (pcle->fl & (PD_BEGINSUBPATH | PD_RESETSTYLE)); } } } /******************************Public*Routine******************************\ * XCLIPOBJ::bGetMorePoints * * This routine gets the next set of points from the path object. If this * routine returns TRUE, it is guranteed that their are at least enough points * for one more line segment. * * returns * TRUE - If there were more points to get * FALSE - if no more points * * History: * 15-Oct-1991 -by- Eric Kutter [erick] * Wrote it. \**************************************************************************/ BOOL XCLIPOBJ::bGetMorePoints(EPATHOBJ *ppo, FLONG *fl) { // if we have already gotten all points, return failure if (pcle->fl & CLO_PATHDONE) { pcle->fl |= CLO_ENUMDONE; return(FALSE); } // if this is a continuation, we need to save the last point if (pcle->cPoints == 1) pcle->ptfx0 = *pcle->pptfx1; // ask the path for some more points PATHDATA pd; if (!(ppo->bEnum(&pd))) { // this is the last chunk of points pcle->fl |= CLO_PATHDONE; // check if we actualy got any. If no, we must be done! if (pd.count == 0) { pcle->fl |= CLO_ENUMDONE; return(FALSE); } } // do a little debugging ASSERTGDI(pd.count > 0, "CLIPPATH: Path is Empty\n"); ASSERTGDI(((pcle->cPoints == 0) ? (pd.flags & PD_BEGINSUBPATH) : TRUE), "XCLIPOBJ::bGetMorePoints - 0 points not at BEGINSUBPATH \n"); // if it is the begining of a sub-path, remember the first point if (pd.flags & PD_BEGINSUBPATH) { pcle->ptfxStartSub = *pd.pptfx; pcle->ptfx0 = *pd.pptfx; // if we only got one point, we had better ask for more if (pd.count == 1) { ASSERTGDI(!(pcle->fl & CLO_PATHDONE),"One point in subpath"); if (!ppo->bEnum(&pd)) { pcle->fl |= CLO_PATHDONE; // check if we actualy got any. If no, we must be done! if (pd.count == 0) { pcle->fl |= CLO_ENUMDONE; return(FALSE); } } pcle->pptfx1 = pd.pptfx; pcle->cPoints = pd.count; } else { // remember that we took two points out of the current set pcle->pptfx1 = pd.pptfx + 1; pcle->cPoints = pd.count - 1; } } else { // this is a continuation of the previous set of points pcle->pptfx1 = pd.pptfx; pcle->cPoints = pd.count; } *fl = pd.flags; return(TRUE); }