⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 runptr.cpp

📁 Windows CE 6.0 Word Application 源码
💻 CPP
📖 第 1 页 / 共 2 页
字号:

/*
 *	CRunPtrBase::AdvanceCp(cch)
 *
 *	@mfunc
 *		Advance this RunPtr by (signed) cch chars.  If it lands on the
 *		end of a run, it automatically goes to the start of the next run
 *		(if one exists). 
 *
 *	@rdesc
 *		Count of characters actually moved
 */
LONG CRunPtrBase::AdvanceCp(
	LONG cch)			//@parm signed count of chars to move this RunPtr by
{
	TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CRunPtrBase::AdvanceCp");

	if (!cch)
		return cch;

	DWORD 	cchSave = cch;

	AssertSz(_iRun == 0 || (_iRun > 0 && _prgRun), "Invalid CRunPtr");

	// No runs, so just update _ich as if there were a run
    if(!IsValid())
    {
        _ich += cch;

		// We have to assume that caller ensures that cch isn't too large,
		// since a runless run ptr doesn't know the cch of the document.
		// But we can check for too-negative values of cch: 
		if( (LONG)_ich < 0 )
		{
			cch = -cch + _ich;				// Calculate actual cch moved
			_ich = 0;
		}
		return cch;
    }

	if(cch < 0)
		while(cch < 0)
		{
			// this cast to LONG is OK, since -cch will be positive
			// (and we aren't likely to have 3 billion characters in 
			// a given run :-)
			if( -cch <= (LONG)_ich )
			{
				_ich += cch;					// Target is in this run
				cch = 0;
				break;
			}
			// otherwise, we need to go to the previous run

			cch += _ich;						// we moved by the number of
												// characters left in the 
												// current run.
			if(_iRun <= 0)						// Already in first run
			{
				_iRun = 0;
				_ich = 0;						// Move to run beginning
				break;
			}
			// move to previous run.
			Assert(_prgRun->Elem(_iRun - 1));

			_ich = _prgRun->Elem(--_iRun)->_cch;
		}
	else
		while(cch > 0)							// Move forward
		{
			const DWORD cchRun = _prgRun->Elem(_iRun)->_cch;
			_ich += cch;

			if(_ich < cchRun)					// Target is in this run
			{
				cch = 0;						// Signal countdown completed
				break;							// (if _ich = cchRun, go to
			}									//  next run)	

			cch = _ich - cchRun;				// Advance to next run
			if(++_iRun >= Count())				// Ran past end, back up to
			{									//  end of story
				--_iRun;
				Assert(_iRun == Count() - 1);
				Assert(_prgRun->Elem(_iRun)->_cch == cchRun);
				_ich = cchRun;
				break;
			}
			_ich = 0;							// Start at new BOL
		}

	// NB! we check the invariant at the end to handle the case where
	// we are updating the cp for a floating range (i.e., we know that
	// the cp is invalid, so we fix it up).  So we have to check for
	// validity *after* the fixup.
	_TEST_INVARIANT_

	return cchSave - cch;						// Return TRUE if countdown
}												// completed

/*
 *	CRunPtrBase::CountRuns(&cRun, cchMax, &tp)
 *
 *	@mfunc
 *		Count characters up to <p cRun> runs away or <p cchMax> chars,
 *		whichever comes first. If the target run and <p cchMax> are both
 *		beyond the corresponding end of the document, count up thru the
 *		closest run (0 or Count() - 1).  The direction of counting is
 *		determined by the sign of <p cRun>.  To count without being limited
 *		by <p cchMax>, set it equal to tomForward. An initial partial
 *		run counts as a run, i.e., if cRun > 0 and _ich < cch in current
 *		run or if cRun < 0 and _ich > 0, that counts as a run.
 *
 *	@rdesc
 *		Return the signed cch counted and set <p cRun> equal to count of runs
 *		actually counted.  If no runs are allocated, the text is treated as
 *		a single run.  If <p cRun> = 0, -_ich is returned. If <p cRun> <gt> 0
 *		and this run ptr points to the end of the last run, no change is made
 *		and 0 is returned.
 *
 *	@devnote
 *		The maximum count capability is included to be able to count units in
 *		a range.  The <p tp> argument is needed for getting the text length
 *		when no runs exist and <p cRun> selects forward counting.
 */
LONG CRunPtrBase::CountRuns (
	LONG &	cRun,			//@parm Count of runs to get cch for
	LONG	cchMax,			//@parm Maximum char count
	LONG	cchText) const	//@parm Text length of associated story
{
	TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CRunPtrBase::CountRuns");

	_TEST_INVARIANT_

	LONG cch;

	if(!cRun)								// Nothing to do
		return 0;

	// Study the following simple special single-run case to get a feel for
	// how run and character counts work and how the initial run contributes
	// to run counting

	if(!_prgRun || !Count())				// No runs instantiated: act as a
	{										//  single run
		if(cRun > 0)						// Count forward
		{
			cch	= cchText - _ich;			// Partial count to end of run
			cRun = 1;						// No more than one run
		}
		else								// Count backward
		{
			cch = -(LONG)_ich;				// Partial count to start of run
			cRun = -1;						// No less than minus one run
		}			
		if(!cch)							// No partial run, so no runs
			cRun = 0;						//  counted
		return cch;
	}

	// General case for which runs are instantiated

	LONG		cb	 = _prgRun->Size();		// Size of text run element
	LONG		iDir;
	DWORD		iRun = _iRun;				// Cache run index for current run
	LONG		j, k;						// Handy integers
	CTxtRun *	pRun = GetRun(0);			// Not NULL since runs exist

	if(cRun < 0)							// Try to count backward cRun runs
	{
		iDir = -1;
		cb	 = -cb;							// Byte count to previous element
		cch	 = _ich;						// Remaining cch in current run
		if(cch)								// If cch != 0, initial run counts
			cRun++;							//  as a run: 1 less for for loop
		cRun = max(cRun, -(LONG)iRun);		// Don't let for loop overshoot
	}
	else
	{										// Try to count forward cRun runs 
		Assert(cRun > 0);
		iDir = 1;
		cch	 = pRun->_cch - _ich;			// Remaining cch in current run
		if(cch)								// If cch != 0, initial run counts
			cRun--;							//  as a run: 1 less for for loop
		k	 = Count() - iRun - 1;			// k = # runs following current run
		cRun = min(cRun, k);				// Don't let for loop overshoot
	}

	k	 = cch;								// Remember if initial cch != 0
	for(j = cRun; j && cch < cchMax; j -= iDir)
	{
		pRun = (CTxtRun *)((BYTE *)pRun + cb);	// Point at following run
		cch += pRun->_cch;					// Add in its count
	}
	if(k)									// Initial partial run counts as
		cRun += iDir;						//  a run
	cRun -= j;								// Discount any runs not counted
											//  if |cch| >= cchMax
	return iDir*cch;						// Return total cch bypassed
}

/*
 *	CRunPtrBase::FindRun (pcpMin, pcpMost, cpMin, cch)
 *
 *	@mfunc
 *		Set *<p pcpMin>  = closest run cpMin <lt>= range cpMin, and
 *		set *<p pcpMost> = closest run cpMost <gt>= range cpMost
 *
 *	@devnote
 *		This routine plays a role analogous to CTxtRange::FindParagraph
 *		(pcpMin, pcpMost), but needs extra arguments since this run ptr does
 *		not know the range cp's.  This run ptr is located at the range active
 *		end, which is determined by the range's signed length <p cch> in
 *		conjunction with <p cpMin>.
 */
void CRunPtrBase::FindRun (
	LONG *pcpMin,			//@parm Out parm for bounding-run cpMin
	LONG *pcpMost,			//@parm Out parm for bounding-run cpMost
	LONG cpMin,				//@parm Range cpMin
	LONG cch,				//@parm Range signed length
	LONG cchText) const		//@parm Story length
{
	TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CRunPtrBase::FindRun");

	BOOL bAdvanceCp;					// Controls AdvanceCp for pcpMost
	CRunPtrBase rp((CRunPtrBase&)(*this));	// Clone this runptr to keep it const

	rp.AdjustForward();					// Select forward run
	if(pcpMin)
	{									// If cch != 0, rp is sure to end up
		bAdvanceCp = cch;				//  at cpMin, so pcpMost needs advance
		if(cch > 0)						// rp is at cpMost, so move it to
			rp.AdvanceCp(-cch);			//  cpMin
		*pcpMin = cpMin - rp._ich;		// Subtract off offset in this run
	}
	else
		bAdvanceCp = cch < 0;			// Need to advance to get pcpMost

	if(pcpMost)
	{
		*pcpMost = cchText;				// Default plain-text value (or
		if(rp.IsValid())				//  single-line value)
		{
			cch = abs(cch);
			if(bAdvanceCp)				// Advance to cpMost = cpMin + cch,
				rp.AdvanceCp(cch);		//  i.e., range's cpMost
			if(cch)
				rp.AdjustBackward();	// Since nondegenerate range
			*pcpMost = cpMin + cch		// Add remaining cch in run to range's
					+ rp.GetCchLeft();	//  cpMost
		}
	}
}

/*
 *	CRunPtrBase::AdjustBackward()
 *
 *	@mfunc
 *		If the cp for this run ptr is at the "boundary" or edge between two
 *		runs, then make sure this run ptr points to the end of the first run.
 *
 *	@comm
 *		This function does nothing unless this run ptr points to the beginning
 *		or the end of a run.  This function may be needed in those cases
 *		because	a cp at the beginning of a run is identical to the cp for the
 *		end of the previous run (if it exists), i.e., such an "edge" cp is
 *		ambiguous, and you may need to be sure that this run ptr points to the
 *		end of the first run.
 *
 *		For example, consider a run that describes characters at cp's 0 to 10
 *		followed by a run that describes characters	at cp's 11 through 12. For
 *		a cp of 11, it is possible for the run ptr to be either at the *end*
 *		of the first run or at the *beginning* of the second run.	 
 *
 *	@rdesc 	nothing
 */
void CRunPtrBase::AdjustBackward()
{
	TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CRunPtrBase::AdjustBackward");

	_TEST_INVARIANT_

	if( !_ich && PrevRun() )				// If at start of run that isn't
		_ich = _prgRun->Elem(_iRun)->_cch;	//  the first, go to end of
}											//  previous run

/*
 *	CRunPtrBase::AdjustForward()
 *
 *	@mfunc
 *		If the cp for this run ptr is at the "boundary" or edge between two
 *		runs, then make sure this run ptr points to the start of the second
 *		run.
 *
 *	@rdesc
 *		nothing
 *	
 *	@xref
 *		<mf CRunPtrBase::AdjustBackward>
 */
void CRunPtrBase::AdjustForward()
{
	TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CRunPtrBase::AdjustForward");

	_TEST_INVARIANT_

	if(!IsValid())
		return;

	CTxtRun *pRun = _prgRun->Elem(_iRun);

	if(pRun->_cch == _ich)					// If at end of run, go to start
		NextRun();							//  of next run (if it exists)
}

/*
 *	CRunPtrBase::IsValid()
 *
 *	@mfunc
 *		indicates whether the current run pointer is in the empty
 *		or NULL states (i.e. "invalid" states).
 *
 *	@rdesc
 *		TRUE is in the empty or NULL state, FALSE otherwise.
 */
BOOL CRunPtrBase::IsValid() const
{
	TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CRunPtrBase::IsValid");

	return _prgRun && _prgRun->Count();
}

/*
 *	CRunPtrBase::SetToNull()
 *
 *	@mfunc
 *		Sets all run pointer information to be NULL. This
 *		is designed to handle the response to clearing document runs
 *		such as when we convert from rich text to plain text.
 *
 *	@rdesc
 *		VOID
 */
void CRunPtrBase::SetToNull() 
{
	TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CRunPtrBase::SetToNull");

	_prgRun = NULL;
	_iRun = 0;
	_ich = 0;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -