text: #include "dnutils.h"
  #include "dninfo.h"
  #include "iobj.h"
  #include "lsdnode.h"
  #include "lscbk.h"
  #include "qheap.h"
  #include "lstext.h"
  #include "lsmem.h"						/* memset() prototype */
  
  
  #define FIsOutOfLine(plsc, plsdn)  \
  		(((plsdn) == NULL) ||   \
  		  (((plsc)->plslineCur->lslinfo.cpLim != 0) && ((plsc)->plslineCur->lslinfo.cpLim <= (plsdn)->cpFirst)))
  
  
  
  
  
  /* F I N D  L I S T  D U P */
  /*----------------------------------------------------------------------------
      %%Function: FindListDup
      %%Contact: igorzv
  
      Visit each node in the list of DNODES, until reaching cpLim
  	Compute dup between start and end points.
  ----------------------------------------------------------------------------*/
  void FindListDup(PLSDNODE plsdnFirst, LSCP cpLim, long *pdup)
  {
  	PLSDNODE plsdn;
  
  	/* tolerate pldnFirst == NULL */
  
  	*pdup = 0;
  	plsdn = plsdnFirst;
  
  	while (plsdn != NULL && plsdn->cpLimOriginal <= cpLim)
  		{
  		Assert(FIsLSDNODE(plsdn));
  		*pdup += DupFromDnode(plsdn);
  		plsdn = plsdn->plsdnNext;
  		}
  
  }
  
  /* F I N D  L I S T  F I N A L  P E N  M O V E M E N T*/
  /*----------------------------------------------------------------------------
      %%Function: FindListFinalPenMovement
      %%Contact: igorzv
  
      Visit each node in the list of DNODES, until reaching cpLim
  	Compute dur dvr dvp  between start and end points.
  ----------------------------------------------------------------------------*/
  void FindListFinalPenMovement(PLSDNODE plsdnFirst, PLSDNODE plsdnLast, long *pdur, long *pdvr, long *pdvp)
  {
  	PLSDNODE plsdn;
  
  	/* tolerate pldnFirst == NULL */
  
  	*pdur = 0;
  	*pdvr = 0;
  	*pdvp = 0;
  	plsdn = plsdnFirst;
  
  	while (plsdn != NULL && plsdn->plsdnPrev != plsdnLast)
  		{
  		Assert(FIsLSDNODE(plsdn));
  		*pdur += DurFromDnode(plsdn);
  		*pdvr += DvrFromDnode(plsdn);
  		*pdvp += DvpFromDnode(plsdn);
  		plsdn = plsdn->plsdnNext;
  		}
  
  }
  
  /* F I N D  L I S T  D I M S */
  /*----------------------------------------------------------------------------
      %%Function: FindListDims
      %%Contact: igorzv
  
      Visit each node in the list of DNODES, until reaching plsdnLast.
  	Compute OBJDIM which describes the list.
  ----------------------------------------------------------------------------*/
  LSERR FindListDims(PLSDNODE plsdnFirst, PLSDNODE plsdnLast, OBJDIM* pobjdimList)
  {
  	PLSDNODE plsdn;
  	long urPen = 0;
  	long urLim = 0;
  	long vpPen = 0;
  	long vrPen = 0;
  	OBJDIM objdimFound;
  	long dvpNode, dvrNode, durNode;
  	long dvpAscentNext;
  	long dvrAscentNext;
  	long dvpDescentNext;
  	long dvrDescentNext;
  	long dvpLineHeight;
  	long dvrLineHeight;
  	POBJDIM pobjdimNode;
  	BOOL fFindLast;
  	OBJDIM* pobjdimLastSkiped = NULL;
  
  
  	/* N.B. Tolerate an empty input list! */
  	Assert(((plsdnFirst == NULL) && (plsdnLast == NULL)) || (FIsLSDNODE(plsdnFirst) && FIsLSDNODE(plsdnLast)));
  
  	/* the most efficient way to put zeroes in heights */
  	memset(&objdimFound, 0, sizeof objdimFound);
  
  	/* quick return if list is empty */
  	if (plsdnFirst == NULL)
  		{
  		*pobjdimList = objdimFound;   /* in objdim will be zeroes */
  		return lserrNone;
  		}
  
  
  	fFindLast = fFalse;
  	for (plsdn = plsdnFirst; !fFindLast ; plsdn = plsdn->plsdnNext)
  		{
  		if (plsdn == NULL)
  		/* we dont found plsdnLast, so return error */
  			return lserrInvalidParameter;
  
  		if (plsdn == plsdnLast)
  			fFindLast = fTrue;
  
  
  		if (plsdn->klsdn == klsdnReal)
  			{
  			pobjdimNode = &plsdn->u.real.objdim;
  			durNode = pobjdimNode->dur;
  			Assert(durNode >= 0);
  			dvrNode = 0;
  			dvpNode = 0;
  
  			dvpAscentNext = pobjdimNode->heightsPres.dvAscent + vpPen;
  			dvrAscentNext = pobjdimNode->heightsRef.dvAscent + vrPen;
  			dvpDescentNext = pobjdimNode->heightsPres.dvDescent - vpPen;
  			dvrDescentNext = pobjdimNode->heightsRef.dvDescent - vrPen;
  			dvpLineHeight = pobjdimNode->heightsPres.dvMultiLineHeight;
  			dvrLineHeight = pobjdimNode->heightsRef.dvMultiLineHeight;
  
  			if (dvrLineHeight != dvHeightIgnore) /* dvrLineHeight == dvHeightIgnore */
  												 /* for us is sign that we  */
  				{						/* should not take into account for height calculation 
  										this dnode */
  				if (objdimFound.heightsPres.dvAscent < dvpAscentNext)
  					objdimFound.heightsPres.dvAscent = dvpAscentNext;
  				if (objdimFound.heightsRef.dvAscent < dvrAscentNext)
  					objdimFound.heightsRef.dvAscent = dvrAscentNext;
  				if (objdimFound.heightsPres.dvDescent < dvpDescentNext)
  					objdimFound.heightsPres.dvDescent = dvpDescentNext;
  				if (objdimFound.heightsRef.dvDescent < dvrDescentNext)
  					objdimFound.heightsRef.dvDescent = dvrDescentNext;
  				if (objdimFound.heightsPres.dvMultiLineHeight < dvpLineHeight)
  					objdimFound.heightsPres.dvMultiLineHeight = dvpLineHeight;
  				if (objdimFound.heightsRef.dvMultiLineHeight < dvrLineHeight)
  					objdimFound.heightsRef.dvMultiLineHeight = dvrLineHeight;
  				}
  
  			else	/*  if final heights is 0, we will take  ascent and desent from
  					   this dnode */
  				{
  				pobjdimLastSkiped = pobjdimNode;
  				}
  					
  
  			}
  		else 			/*  klsdnPenOrBorder*/
  			{  
  			dvpNode = plsdn->u.pen.dvp;
  			durNode = plsdn->u.pen.dur;
  			dvrNode = plsdn->u.pen.dvr;
  			}
  
  
  		vpPen += dvpNode;
  		urPen += durNode;
  		vrPen += dvrNode;
  		if (urLim < urPen)
  			urLim = urPen;
  		}
  
  	if (objdimFound.heightsRef.dvAscent == 0 && objdimFound.heightsRef.dvDescent == 0
  		&& pobjdimLastSkiped != NULL)
  		{
  		objdimFound.heightsPres.dvAscent = pobjdimLastSkiped->heightsPres.dvAscent + vpPen;
  		objdimFound.heightsRef.dvAscent = pobjdimLastSkiped->heightsRef.dvAscent + vrPen;
  		objdimFound.heightsPres.dvDescent = pobjdimLastSkiped->heightsPres.dvDescent - vpPen;
  		objdimFound.heightsRef.dvDescent = pobjdimLastSkiped->heightsRef.dvDescent - vrPen;
  		objdimFound.heightsPres.dvMultiLineHeight = dvHeightIgnore;
  		objdimFound.heightsRef.dvMultiLineHeight = dvHeightIgnore;
  		}
  
  
  	*pobjdimList = objdimFound;
  	pobjdimList->dur = urLim;
  	return lserrNone;
  }
  
  
  
  
  /* D E S T R O Y  D N O D E  L I S T   */
  /*----------------------------------------------------------------------------
      %%Function: DestroyDnodeList
      %%Contact: igorzv
  
  Parameters:
  	plscbk				-	(IN) callbacks
  	pols				-	(IN) pols to pass for callbacks
  	plsiobjcontext		-	(IN) object handlers 
  	plsdn				-	(IN) first dnode in list
  	fDontReleaseRuns	-	(IN) not to call release run
  ----------------------------------------------------------------------------*/
  LSERR DestroyDnodeList(LSCBK* plscbk, POLS pols, PLSIOBJCONTEXT plsiobjcontext,
  					   PLSDNODE plsdn, BOOL fDontReleaseRuns)
  {
  	LSERR lserr, lserrFinal = lserrNone;
  	PLSDNODE plsdnNext;
  	PDOBJ pdobj;
  	PLSRUN plsrun;
  	DWORD iobj;
  
  
  	if (plsdn == NULL)
  		return lserrNone;
  
  	Assert(FIsLSDNODE(plsdn));
  
  	/* link with this dnode should  be broken before */
  	Assert(plsdn->plsdnPrev == NULL || plsdn->plsdnPrev->plsdnNext != plsdn );
  
  	for (;  plsdn != NULL;  plsdn = plsdnNext)
  		{
  
  		Assert(FIsLSDNODE(plsdn));
  
  		if (plsdn->klsdn == klsdnReal)
  			{
  			if (plsdn->u.real.pinfosubl != NULL)
  				{
  				if (plsdn->u.real.pinfosubl->rgpsubl != NULL)
  					{
  					plscbk->pfnDisposePtr(pols, plsdn->u.real.pinfosubl->rgpsubl);
  					}
  
  				plscbk->pfnDisposePtr(pols, plsdn->u.real.pinfosubl);
  				}
  
  			iobj = plsdn->u.real.lschp.idObj;
  			plsrun = plsdn->u.real.plsrun;
  			pdobj = plsdn->u.real.pdobj;
  			}
  		else
  			{
  			Assert (FIsDnodePen(plsdn) || FIsDnodeBorder(plsdn));
  			iobj = 0;
  			plsrun = NULL;
  			pdobj = NULL;
  			}
  
  		if (plsrun != NULL && !fDontReleaseRuns)
  			{
  			lserr = plscbk->pfnReleaseRun(pols, plsrun);
  			if (lserr != lserrNone && lserrFinal == lserrNone)
  				lserrFinal = lserr;
  			}
  
  		if (pdobj != NULL)
  			{
  			lserr = (PLsimFromLsc(plsiobjcontext, iobj))->pfnDestroyDObj (pdobj);
  			if (lserr != lserrNone && lserrFinal == lserrNone)
  				lserrFinal = lserr;
  			}
  
  		plsdn->tag = tagInvalid;
  		plsdnNext = plsdn->plsdnNext;
  		}
  
  	return lserrFinal;
  }
  
  
  /* ---------------------------------------------------------------------- */
  
  /*  D U R  B O R D E R  F R O M  D N O D E  I N S I D E*/
  /*----------------------------------------------------------------------------
      %%Function: DurBorderFromDnodeInside
      %%Contact: igorzv
  Parameters:
  	plsdn	-	(IN) dnode inside borders 
  ----------------------------------------------------------------------------*/
  long DurBorderFromDnodeInside(PLSDNODE plsdn) /* IN: dnode inside borders */
  	{
  	PLSDNODE plsdnBorder = plsdn;
  	while (!FIsDnodeBorder(plsdnBorder))
  		{
  		plsdnBorder = plsdnBorder->plsdnPrev;
  		Assert(FIsLSDNODE(plsdnBorder));
  		}
  	
  	Assert(FIsDnodeBorder(plsdnBorder));
  	Assert(plsdnBorder->fOpenBorder);
  				
  	return plsdnBorder->u.pen.dur;
  				
  	}
  
  /* ---------------------------------------------------------------------- */
  
  /*  F  S P A C E S  O N L Y*/
  /*----------------------------------------------------------------------------
      %%Function: FSpacesOnly
      %%Contact: igorzv
  Parameters:
  	plsdn	-	(IN) dnode 
  	iObjText-	(IN) id for text dnode 
  ----------------------------------------------------------------------------*/
  BOOL FSpacesOnly(PLSDNODE plsdn, DWORD iObjText)
  	{
  	DWORD dcpTrailing;
  	long durTrailing;
  
  	if (FIsDnodeSplat(plsdn))
  		return fTrue;
  	else if (FIsDnodeReal(plsdn) 
  			 && (IdObjFromDnode(plsdn) == iObjText)
  			 && !(plsdn->fTab))
  		{
  		GetTrailInfoText(PdobjFromDnode(plsdn), plsdn->dcp,
  					&dcpTrailing, &durTrailing);	
  		if (dcpTrailing == plsdn->dcp)
  			return fTrue;
  		}
  	return fFalse;
  	}
  