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

📄 frunptr.cpp

📁 Windows CE 6.0 Word Application 源码
💻 CPP
📖 第 1 页 / 共 2 页
字号:
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft shared
// source or premium shared source license agreement under which you licensed
// this source code. If you did not accept the terms of the license agreement,
// you are not authorized to use this source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the SOURCE.RTF on your install media or the root of your tools installation.
// THE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES.
//
/*
 *	@doc	INTERNAL
 *
 *	@module	FRUNPTR.C -- FormatRunPtr methods |
 *
 *		common code to handle character and paragraph format runs
 *	
 *	Original Authors: <nl>
 *		Original RichEdit code: David R. Fulmer <nl>
 *		Christian Fortini <nl>
 *		Murray Sargent <nl>
 *
 *	History:
 *		6/25/95		alexgo	convert to use Auto-Doc and simplified backing
 *		store model
 *
 *	@devnote
 *		BOR and EOR mean Beginning Of Run and End Of Run, respectively
 */

#include "_common.h"
#include "_edit.h"
#include "_frunptr.h"
#include "_rtext.h"

ASSERTDATA

//
//	Invariant stuff
//
#define DEBUG_CLASSNAME	CFormatRunPtr

#include "_invar.h"

#ifdef DEBUG
/*
 *	CFormatRunPtr::Invariant
 *
 *	@mfunc	Invariant for format run pointers
 *
 *	@rdesc	BOOL
 */
BOOL CFormatRunPtr::Invariant() const
{
	if( IsValid() )
	{
		CFormatRun *prun = GetRun(0);

		if( prun && _iRun != 0 )
		{
			Assert( (LONG)prun->_cch > 0 );
		}
	}

	return CRunPtrBase::Invariant();
}
#endif

/*
 *	CFormatRunPtr::InitRuns(ich, cch, iFormat, ppfrs)
 *
 *	@mfunc
 *		Setup this format run ptr for rich-text operation, namely,
 *		allocate CArray<lt>CFormatRun<gt> if not allocated, assign it to this
 *		run ptr's _prgRun, add initial run if no runs are present, and store
 *		initial cch and ich
 *	
 *	@rdesc
 *		TRUE if succeeds
 */
BOOL CFormatRunPtr::InitRuns(
	DWORD ich,				//@parm # chars in initial run
	DWORD cch,				//@parm char offset in initial run
	CFormatRuns **ppfrs)	//@parm ptr to CFormatRuns ptr
{
	TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CFormatRunPtr::InitRuns");

	_TEST_INVARIANT_

	AssertSz( ppfrs,
		"FRP::InitRuns: illegal ptr to runs");
	AssertSz( !IsValid(),
		"FRP::InitRuns: ptr already valid");

	if(!*ppfrs)									// Allocate format runs
	{
		_prgRun = (CRunArray *) new CFormatRuns();
		if(!_prgRun)
			goto NoRAM;
		*ppfrs = (CFormatRuns *)_prgRun;
	}
	else										// Format runs already alloc'd
		_prgRun = (CRunArray *)*ppfrs;			// Cache ptr to runs

	if(!Count())								// No runs yet, so add one
	{
		CFormatRun *pRun= Add(1, NULL);
		if(!pRun)
			goto NoRAM;
		_ich			= ich;
		pRun->_cch		= cch;					// Define its _cch
		pRun->_iFormat 	= -1;					//  and _iFormat
	}
	else
		BindToCp(ich);							// Format runs are in place

	return TRUE;

NoRAM:
	TRACEERRSZSC("CFormatRunPtr::InitRuns: Out Of RAM", E_OUTOFMEMORY);
	return FALSE;
}


/*
 *	CFormatRunPtr::Delete(cch, pf, cchMove)
 *	
 *	@mfunc
 *		Delete/modify runs starting at this run ptr up to cch chars. <nl>
 *		There are 7 possibilities: <nl>
 *		1.	cch comes out of this run with count left over, i.e.,
 *			cch <lt>= (*this)->_cch - _ich && (*this)->_cch > cch
 *			(simple: no runs deleted/merged, just subtract cch) <nl>
 *		2.	cch comes out of this run and empties run and doc
 *			(simple: no runs left to delete/merge) <nl>
 *		3.	cch comes out of this run and empties run, which is last
 *			(need to delete run, no merge possibility) <nl>
 *		4.	cch comes out of this run and empties run, which is first
 *			(need to delete run, no merge possibility) <nl>
 *		5.	cch exceeds count available in this run and this run is last
 *			(simple: treat as 3.)  <nl>
 *		6.	cch comes out of this run and empties run with runs before
 *			and after (need to delete run; merge possibility) <nl>
 *		7.	cch comes partly out of this run and partly out of later run(s)
 *			(may need to delete and merge) <nl>
 *
 *	@comm
 *		PARAFORMATs have two special cases that use the cchMove argument set
 *		up in CRchTxtPtr::ReplaceRange().
 */
void CFormatRunPtr::Delete(
	DWORD		  cch,		//@parm # chars to modify format runs for
	IFormatCache *pf,		//@parm IFormatCache ptr for ReleaseFormat
	LONG		  cchMove)	//@parm cch to move between runs (always 0 for CF)
{
	TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CFormatRunPtr::Delete");

	_TEST_INVARIANT_

	// we should not have any boundary cases for empty or NULL pointers.  
	// (i.e. if there's no text, then nobody should be calling delete).

	Assert(IsValid());

	DWORD			cchEnd = 0;				// Probably unnecessary: see below
	DWORD			cRun = 1;
	BOOL			fDelAll = FALSE;
	BOOL			fLast = (_iRun == Count() - 1);
	LONG			ifmtEnd, ifmtStart;
	DWORD			j;
	CFormatRun *	pRun = Elem(_iRun);
	CFormatRun *	pRunRp;
	DWORD			cchChunk = pRun->_cch - _ich;
	CFormatRunPtr	rp(*this);				// Clone this run ptr

	rp.AdjustBackward();					// If at BOR, move to prev EOR
	ifmtStart = rp.GetRun(0)->_iFormat;		//  to get start format
	rp = *this;								// In case RpAdjustCp() backed up

// Process deletes confined to this run first, since their logic tends to
// clutter up other cases

	AssertSz(cch >= 0,
		"FRP::Delete: cch < 0");

	if(fLast)								// Handle oversized cch on last
		cch = min(cch, cchChunk); 			//  run here

	if(cch <= cchChunk)						// cch comes out of this run
	{
		pRun->_cch -= cch;
		Assert((LONG)pRun->_cch >= 0);
		if(cchMove)							// If nonzero here, we are
		{									//  deleting EOP at end of run
			rp.AdjustForward();				// Adjust rp to beginning of
			goto move;						//  next run and go move cchMove
		}									//  chars back into this run
		if(pRun->_cch)						// Something left in run: done
			return;
											// Note: _ich = 0
		if(!_iRun || fLast)					// This run is either first
		{									//  or last
			AdjustBackward();				// If last, go to prev EOR
			if(_ich)						// This run is empty so delete
				cRun++;						// Compensate for cRun-- coming up
			ifmtStart = -2;					// No runs eligible for merging
		}									//  so use unmatchable ifmtStart
		rp.NextRun();						// Set up to get next _iFormat
	}		
	else
	{
		rp.AdvanceCp(cch);					// Move clone to end of delete
		pRunRp = rp.GetRun(0);
		cRun = rp._iRun - _iRun				// If at EOR, then need to add
			 + (rp._ich == pRunRp->_cch);	//  one more run to delete
		AssertSz(cRun > 0,
			"FRP: bogus runptr");
		pRun->_cch = _ich;					// Shorten this run to _ich chars
		pRunRp->_cch -= rp._ich;			// Shorten last run by rp._ich
		Assert((LONG)pRunRp->_cch >= 0);
		rp._ich = 0;

		if (!_iRun)		  					// First run?
		{
			ifmtStart = -2;					// Then we cannot merge runs so
		}									//  set to unmergable format
	}

	ifmtEnd = -3;							// Default invalid format at end
	if(rp.IsValid())
	{
		// FUTURE (murrays): probably rp is always valid here now and
		// pRun->_cch is nonzero
		pRun = rp.GetRun(0);
		if (pRun->_cch)                     // run not empty
		{
			ifmtEnd = pRun->_iFormat;		// Remember end format and count
			cchEnd  = pRun->_cch;			//  in case of merge
		}
		else if(rp._iRun != rp.Count() - 1)	// run not last
		{
			pRun = rp.GetRun(1);
			ifmtEnd = pRun->_iFormat;		// Remember end format and count
			cchEnd  = pRun->_cch;			//  in case of merge
		}
	}

	rp = *this;								// Default to delete this run
	if(_ich)								// There are chars in this run
	{
		if(cchMove + _ich == 0)				// Need to combine all chars of
		{									//  this run with run after del,
			pf->AddRefFormat(ifmtEnd);		//  so setup merge below using
			ifmtStart = ifmtEnd;			//  ifmtEnd. This run then takes
			GetRun(0)->_iFormat = ifmtEnd;	//  place of run after del.
			cchMove = 0;					// cchMove all accounted for
		}
		rp.NextRun();						// Don't delete this run; start
		cRun--;								//  with next one
	}

	AdjustBackward();						// If !_ich, go to prev EOR

	if(ifmtEnd == ifmtStart && ifmtEnd >=0)	// Same formats: merge runs
	{
		GetRun(0)->_cch += cchEnd;			// Add last-run cch to this one's
		Assert((LONG)GetRun(0)->_cch >= 0);
		cRun++;								// Setup to eat last run
	}

	if(cRun > 0)							// There are run(s) to delete
	{
		pRun = rp.GetRun(0);				// Point at run(s) to delete
		for(j = 0; j < cRun; j++, IncPtr(pRun))
			pf->ReleaseFormat(pRun->_iFormat);

		rp.Remove(cRun, AF_KEEPMEM);
		if(!Count())						// If no more runs, keep this rp
			_ich = _iRun = 0;				//  valid by pointing at cp = 0
	}

move:
	if(cchMove)								// Need to move some cch between
	{										//  this run and next (See
		GetRun(0)->_cch += cchMove;			//  CRchTxtPtr::ReplaceRange())

		rp.GetRun(0)->_cch -= cchMove;

		Assert((LONG)GetRun(0)->_cch >= 0);
		Assert((LONG)rp.GetRun(0)->_cch >= 0);

		Assert(_iRun < rp._iRun);

		if(!rp.GetRun(0)->_cch)				// If all chars moved out of rp's
			rp.Remove(1, AF_KEEPMEM);		//  run, delete it

		if(cchMove < 0)						// Moved -cchMove chars from this
		{									//  run to next
			if( !GetRun(0)->_cch )
				Remove(1, AF_KEEPMEM);
			else
				_iRun++;					// Keep this run ptr in sync with

			_ich = -cchMove;				//  cp (can't use NextRun() due
		}									//  to Invariants)
	}
	AdjustForward();						// Don't leave ptr at EOR unless
}											//  there are no more runs

/*
 *	CFormatRunPtr::InsertFormat(cch, ifmt, pf)
 *	
 *	@mfunc
 *		Insert cch chars with format ifmt into format runs starting at
 *		this run ptr	
 *
 *	@rdesc
 *		count of characters added
 *
 *	@devnote	
 *		It is the caller's responsibility to ensure that we are in the
 *		"normal" or "empty" state.  A format run pointer doesn't know about
 *		CTxtStory, so it can't create the run array without outside help.
 */
DWORD CFormatRunPtr::InsertFormat(
	DWORD cch,				//@parm # chars to insert
	LONG ifmt,				//@parm format to use
	IFormatCache *pf)		//@parm pointer to IFormatCache to AddRefFormat
{
	TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CFormatRunPtr::InsertFormat");

	Assert(_prgRun);
	LONG		cRun;
	CFormatRun *pRun = NULL;
	CFormatRun *pRunPrev;
	LONG		cchRun;						// Current-run length,
	LONG		ich;						//  offset, and
	LONG		iFormat; 					//  format

	_TEST_INVARIANT_

	Assert(_prgRun);
	if(!IsValid())
	{		
		// Empty run case (occurs when inserting after all text is deleted)
		pRun = Add(1, NULL);
		if (NULL == pRun)
		{
		    AssertSz(pRun, "Memory Allocation Failure in CFormatRunPtr::InsertFormat");
		    return 0;
		}    
		goto StoreNewRunData;				// (located at end of function)
	}

	// Go to previous run if at a boundary case
	AdjustBackward();
	pRun = Elem(_iRun);

	if (NULL == pRun)
	{
	    AssertSz(pRun, "Memory Allocation Failure in CFormatRunPtr::InsertFormat");
	    return 0;
	}    

	ich 	= _ich;							// Try other cases
	cchRun 	= pRun->_cch;
	iFormat = pRun->_iFormat;

	// 
	// Same run case.  Note that there is an additional boundary case; if we
	// are the _end_ of one run, then the next run may have the necessary 
	// format.
	//

	if(ifmt == iFormat)						// IP already has correct fmt
	{
		pRun->_cch	+= cch;
		_ich		+= cch;					// Inc offset to keep in sync
		return cch;
	}
	else if( _ich == pRun->_cch && _iRun < (_prgRun->Count() - 1) )
	{
		AdjustForward();
		pRun = Elem(_iRun);

		Assert(pRun);

		if( pRun->_iFormat == ifmt )
		{
			pRun->_cch += cch;
			_ich += cch;
			return cch;
		}
		AdjustBackward();
	}
		 

	//
	// Prior run case (needed when formatting change occurs on line break
	//		and caret is at beginning of new line)
	// 

	if(!ich && _iRun > 0 )					// IP at start of run
	{
		pRunPrev = GetPtr(pRun, -1);
		if( ifmt == pRunPrev->_iFormat)		// Prev run has same format:
		{									//  add count to prev run and
			pRunPrev->_cch += cch;
			return cch;
		}
	}

	//
	// Create new run[s] cases.  There is a special case for a format
	//	run of zero length: just re-use it.

	if( pRun->_cch == 0 )
	{
		// This assert has been toned down to ignore a plain text control being forced into IME Rich Composition.
		AssertSz( /* FALSE */ pRun->_iFormat == -1 && Count() == 1, "CFormatRunPtr::InsertFormat: 0-length run");
		pf->ReleaseFormat(pRun->_iFormat);
	}
	else									// Need to create 1 or 2 new
	{										//  runs for insertion
		cRun = 1;							// Default 1 new run
		if(ich && ich < cchRun)				// Not at beginning or end of
			cRun++;							//  run, so need two new runs

		// The following insert call adds one or two runs at the current
		// position. If the new run is inserted at the beginning or end
		// of the current run, the latter needs no change; however, if
		// the new run splits the current run in two, both pieces have
		// to be updated (cRun == 2 case).

		pRun = Insert(cRun);				// Insert cRun run(s)
		if(!pRun)							// Out of RAM. Can't insert
		{									//  new format, but can keep
			_ich += cch;					//  run ptr and format runs
			GetRun(0)->_cch += cch;			//  valid.  Note: doesn't
			return cch;						//  signal any error; no access
		}									//  to _ped->_fErrSpace

		if(ich)								// Not at beginning of run,
		{
			pRunPrev = pRun;				// Previous run is current run
			IncPtr(pRun);					// New run is next run
			VALIDATE_PTR(pRun);
			NextRun();						// Point this runptr at it too
			if(cRun == 2)					// Are splitting current run
			{								// _iFormat's are already set
				AssertSz(pRunPrev->_iFormat == iFormat,
					"CFormatRunPtr::InsertFormat: bad format inserted");
				pRunPrev->_cch = ich;		// Divide up original cch
				GetPtr(pRun, 1)->_cch		//  accordingly
					= cchRun - ich;
				pf->AddRefFormat(iFormat);	// Addref iFormat for extra run
			}
		}
	}

StoreNewRunData:
	pf->AddRefFormat(ifmt);					// Addref ifmt
	pRun->_iFormat	= ifmt;					// Store insert format and count  
	pRun->_cch		= cch;					//  of new run
	_ich			= cch;					// cp goes at end of insertion

	return cch;
}

/*
 *	CFormatRunPtr::MergeRuns(iRun, pf)
 *	
 *	@mfunc
 *		Merge adjacent runs that have the same format between this run 
 *		<md CFormatRunPtr::_iRun> and that for <p iRun>		
 *
 *	@comm
 *		Changes this run ptr
 *
 */
void CFormatRunPtr::MergeRuns(
	DWORD iRun, 			//@parm last run to check (can preceed or follow 
							// <md CFormatRunPtr::_iRun>)
	IFormatCache *pf)		//@parm pointer to IFormatCache to ReleaseFormat
{
	TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CFormatRunPtr::MergeRuns");

	DWORD	cch;
	LONG	cRuns		= iRun - _iRun;
	LONG	iDirection	= 1;				// Default going forward
	LONG	iFormat;						// Temporary iFormat

	_TEST_INVARIANT_

	if(cRuns < 0)
	{
		cRuns = -cRuns;
		iDirection = -1;
	}
	if(!IsValid())							// Allow starting run to be
		ChgRun(iDirection);					//  invalid

	while(cRuns--)
	{
		iFormat = GetRun(0)->_iFormat;

        if( GetRun(0)->_cch == 0 && !_iRun && _iRun < (Count() -1) )
        {
            if( iDirection > 0 )
                PrevRun();
            pf->ReleaseFormat(iFormat);
            Remove(1, AF_KEEPMEM);
            continue;
        }

		if( !ChgRun(iDirection) )			// Go to next (or prev) run
			return;							// No more runs to check

⌨️ 快捷键说明

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