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

📄 dispml.cpp

📁 Windows CE 6.0 Word Application 源码
💻 CPP
📖 第 1 页 / 共 5 页
字号:
	_yCalcMax = 0;							// Set both maxes to start of text
	_cpCalcMax = 0;

	// Don't stop at the bottom of the view if we're bottomless and we're active.
	if (!_ped->TxGetAutoSize() && IsActive())
	{
		// be lazy - don't bother going past visible portion
		_cpWait = -1;
		_yWait = -1;
		fWait = TRUE;
	}

	// Init measurer at cp = 0
	CMeasurer me(this);
 	
	// The following loop generates new lines
	while( (LONG)me.GetCp() < cchText )
	{
		// Add one new line
		pliNew = Add(1, NULL);
		if (!pliNew)
		{
			_ped->GetCallMgr()->SetOutOfMemory();
			TRACEWARNSZ("Out of memory Recalc'ing lines");
			goto err;
		}

		// stuff text into new line
		UINT uiFlags = MEASURE_BREAKATWORD | (fFirstInPara ? MEASURE_FIRSTINPARA : 0);

    	Tracef(TRCSEVINFO, "Measuring new line from cp = %d", me.GetCp());

		if(!pliNew->Measure(me, -1, uiFlags))
		{
			Assert(FALSE);
			goto err;
		}

		fFirstInPara = pliNew->_cchEOP;
		yHeight += pliNew->GetHeight();
		_cpCalcMax = me.GetCp();

		if (fWait)
		{
			// Do we want to do a background recalc? - the answer is yes if
			// three things are true: (1) We have recalc'd beyond the old first
			// visible character, (2) We have recalc'd beyond the visible 
			// portion of the screen and (3) we have gone beyond the next
			// cExtraBeforeLazy lines to make page down go faster.

			if (fWaitingForFirstVisible)
			{
				if ((LONG) me.GetCp() > _cpFirstVisible)
				{
					_yWait = yHeight + yHeightView;
					fWaitingForFirstVisible = FALSE;
				}
			}
			else if ((yHeight > _yWait) && cliWait-- <= 0)
			{
				fDone = FALSE;
				break;
			}
		}
	}

	_yCalcMax = yHeight;
	_fRecalcDone = fDone;
    _fNeedRecalc = FALSE;
	yHeightScrollNew = CalcScrollHeight(yHeight);

	if((fDone 
		&& ((yHeight != _yHeight) || (yHeightScrollNew != yHeightScrollOld)))
		|| (yHeightScrollNew > yHeightScrollOld))
	{
		_yHeight = yHeight;
		_fViewChanged = TRUE;
	}

	xWidth = CalcDisplayWidth();
    if((fDone && (xWidth != _xWidth)) || (xWidth > _xWidth))
    {
        _xWidth = xWidth;
		_fViewChanged = TRUE;
    }    

	Tracef(TRCSEVINFO, "CDisplayML::RecalcLine() - Done. Recalced down to line #%d", Count());

	if(!fDone)						// if not done, do rest in background
	{
		fDone = StartBackgroundRecalc();
	}

	if (fDone)
	{
		_yWait = -1;
		_cpWait = -1;
		CheckLineArray();
		_fLineRecalcErr = FALSE;
	}

#ifdef DEBUG
	if( 1 )
    {
		_TEST_INVARIANT_
	}
#endif // DEBUG

	return TRUE;

err:
	TRACEERRORSZ("CDisplayML::RecalcLines() failed");

	if(!_fLineRecalcErr)
	{
		_cpCalcMax = me.GetCp();
		_yCalcMax = yHeight;
		_fLineRecalcErr = TRUE;
		_ped->GetCallMgr()->SetOutOfMemory();
		_fLineRecalcErr = FALSE;			//  fix up CArray & bail
	}

	return FALSE;
}

/*
 *	CDisplayML::RecalcLines(tpFirst, cchOld, cchNew, fBackground, fWait, pled)
 *
 *	@mfunc
 *		Recompute line breaks after text modification
 *
 *	@rdesc
 *		TRUE if success
 */						     
BOOL CDisplayML::RecalcLines (
	const CRchTxtPtr &tpFirst,	//@parm Where change happened
	LONG cchOld,				//@parm Count of chars deleted
	LONG cchNew,				//@parm Count of chars added
	BOOL fBackground,			//@parm This method called as background process
	BOOL fWait,					//@parm Recalc lines down to _cpWait/_yWait; then be lazy
	CLed *pled)					//@parm Records & returns impact of edit on lines (can be NULL)
{
	TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplayML::RecalcLines");
			  		  
	LONG		cchEdit;
	LONG		cchSkip;
	LONG		cli = 0;
	LONG		cliBackedUp = 0;
	LONG		cliWait = cExtraBeforeLazy;	
	BOOL		fDone = TRUE;
	BOOL		fFirstInPara = TRUE;
	LONG		ili;
	CLed		led;
	LONG		lT;							// long Temporary
	CLine *		pliNew;
	CLine *		pli = NULL;
	CLinePtr	rpOld(this);
	LONG		xWidth;
	LONG		yHeight;
	LONG		yHeightPrev = 0;
    LONG        cchText = _ped->GetTextLength();
    UINT        uiFlags;
	BOOL 		fReplaceResult;
	BOOL		fTryForMatch = TRUE;
	LONG		yHeightScrollOld = GetMaxYScroll();
	LONG		yHeightScrollNew;
	WORD		wNumber = 0;

	if (!pled)
		pled = &led;

#ifdef DEBUG
	LONG		cp;

	if(tpFirst.GetCp() > _cpCalcMax)
		Tracef(TRCSEVERR, "tpFirst %ld, _cpCalcMax %ld", tpFirst.GetCp(), _cpCalcMax);

	AssertSz(tpFirst.GetCp() <= _cpCalcMax, 
		"CDisplayML::RecalcLines Caller didn't setup RecalcLines()");

	AssertSz(!(fWait && fBackground),
		"CDisplayML::RecalcLines wait and background both true");

	AssertSz(!(fWait && (-1 == _cpWait) && (-1 == _yWait)),
		"CDisplayML::RecalcLines background recalc parms invalid");
#endif

	// We will not use background recalc if this is already a background recalc,
	// or if the control is not active or if this is an auto sized control.
	if(!IsActive() || _ped->TxGetAutoSize())
	{
		fWait = FALSE;
	}

	// Init line pointer on old CLineArray and backup to start of line
	rpOld.RpSetCp(tpFirst.GetCp(), FALSE);
	cchSkip = rpOld.RpGetIch();
	rpOld.RpAdvanceCp(-cchSkip);			// Point rp at 1st char in line

	ili = rpOld;							// Save line # at change for
	if(ili && (IsInOutlineView() ||			//  numbering. Back up if not
		tpFirst.GetPF()->IsListNumbered()))	//  first number in list or if
	{										//  in OutlineView (Outline
		ili--;								//  symbol may change)
	}

	// Back up at least one line in case we can now fit more on it
	// If on a line border, e.g., just inserted an EOP, backup 2; else 1
	lT = !cchSkip + 1;

	while(lT-- > 0 && rpOld > 0 && (!rpOld[-1]._cchEOP || ili < rpOld))
	{
		cliBackedUp++;
		rpOld--;
		cchSkip += rpOld->_cch;
	}

	// Init measurer at tpFirst
	CMeasurer me(this, tpFirst);

	me.Advance(-cchSkip);					// Point at start of text to measure
	cchEdit = cchNew + cchSkip;				// Number of chars affected by edit
	me.SetNumber(rpOld.GetNumber());		// Initialize list number
	
	// Determine whether we're on first line of paragraph
	if(rpOld > 0)
	{
		fFirstInPara = rpOld[-1]._cchEOP;
		AssertSz(me.GetCp() >= _cpCalcMax ||
				 !(rpOld->_bFlags & fliFirstInPara) == !fFirstInPara, 
				 "fHasEOL & fFirstInPara disagree");
	}

	yHeight = YposFromLine(rpOld);

	// Update first-affected and pre-edit-match lines in pled
	pled->_iliFirst = rpOld;
	pled->_cpFirst	= pled->_cpMatchOld	= me.GetCp();
	pled->_yFirst	= pled->_yMatchOld	= yHeight;
	AssertSz(pled->_yFirst >= 0, "CDisplayML::RecalcLines _yFirst < 0");
	
	Tracef(TRCSEVINFO, "Start recalcing from line #%d, cp=%d", pled->_iliFirst, pled->_cpFirst);

	// If we are past the requested area to recalc and background recalc is
	// allowed, then just go directly to background recalc. If there is no
	// height, we just go a head and calculate some lines anyway. This
	// prevents any weird background recalcs from occuring when it is
	// unnecessary to go into background recalc.
	if(fWait && _yWait > 0 && yHeight > _yWait && (LONG)me.GetCp() > _cpWait)
	{
		// Reset the recalc max to where we would have started the recalc
		_cpCalcMax = (LONG) me.GetCp();

		// Remove all old lines from here on
		rpOld.Remove(-1, AF_KEEPMEM);

		// Start up the background recalc
		StartBackgroundRecalc();		
		pled->SetMax(this);
		return TRUE;
	}

	// In case of error, set both maxes to where we are now
	_yCalcMax = yHeight;
	_cpCalcMax = me.GetCp();

	// Create or reuse new CArray of lines
	if (!_prgliNew && !(_prgliNew = new CLineArray()))
	{
		TRACEWARNSZ("CDisplayML::RecalcLines unable to alloc CLineArray");
		goto errspace;
	}
	_prgliNew->Clear(AF_KEEPMEM);
    pliNew = NULL;

	// The following loop generates new lines for each line we backed
	// up over and for lines directly affected by edit
	while(cchEdit > 0)
	{
		pliNew = _prgliNew->Add(1, NULL);		// Add one new line
		if (!pliNew)
		{
			TRACEWARNSZ("CDisplayML::RecalcLines unable to alloc additional CLine in CLineArray");
			goto errspace;
		}

		// Can't reuse old results if we've got a target device
		// For SPEED: it'd be nice to cache a few values when we do have a
		// target device - a good caching heuristic could halve the measuring
		const LONG cchNonWhite = rpOld.IsValid() ? 
			(rpOld->_cch - rpOld->_cchWhite ) : 0;

		if(cchSkip > 0 && cchSkip >= cchNonWhite && !IsInOutlineView() && 
			(NULL == _pddTarget || !_pddTarget->IsValid()))
		{
			me.NewLine(*rpOld);			// Don't remeasure anything we
			me.Advance(cchNonWhite);	//  already have valid info on
			me._cch = cchNonWhite;
			me._xWidth = rpOld->_xWidth;

			// clear out any of the old flags _except_ for tabs and OLE or
			// of screen. Note that this algorithm is somewhat bogus; there 
			// is no guarantee that the line still matches the flag state.  
			// However,those flags are simply 'hints'--i.e. the line _may_ 
			// be in that state.  Keeping those flags set will result
			// in a minor slowdown for rendering the line.
			me._bFlags &= (fliHasTabs | fliHasOle | fliUseOffScreenDC);

			if (rpOld->_bFlags & fliOffScreenOnce)
				me._bFlags &= ~fliUseOffScreenDC;
			me._cchEOP = 0;
		}
		else
			me.NewLine(fFirstInPara);			// Remeasure from start of line

		// Stuff text into new line
		uiFlags = MEASURE_BREAKATWORD | (fFirstInPara ? MEASURE_FIRSTINPARA : 0);

    	Tracef(TRCSEVINFO, "Measuring new line from cp = %d", me.GetCp());

		if (!me.MeasureLine(-1, -1, uiFlags))
		{
			Assert(FALSE);
			goto err;
		}

		*pliNew = me;
      
		if( pliNew->_cch == 0 )
		{
			TRACEWARNSZ(
           "CDisplayML::RecalcLines measure returned a zero length line");
			goto errspace;
		}

		// Calculate on what line the edit started. We do this because
		// we want to render the first edited line off screen so if
		// the line is being edited via the key board we don't clip
		// any characters.
		if(cchSkip > 0)
		{
			// Check whether we backed up and the line we are examining
			// changed at all. Even if it didn't change in outline view
			// have to redraw in case outline symbol changes
			if(cliBackedUp != 0 && cchSkip >= (LONG)pliNew->_cch 
				&& pliNew->IsEqual(*rpOld) && !IsInOutlineView())
			{
				// perfect match, this line was not the first edited.
               	Tracef(TRCSEVINFO, "New line matched old line #%d", (LONG)rpOld);

				cchSkip -= rpOld->_cch;

				// Update first affected line and match in pled
				pled->_iliFirst++;
				pled->_cpFirst	  += rpOld->_cch;
				pled->_cpMatchOld += rpOld->_cch;
				pled->_yFirst	  += rpOld->GetHeight();
				AssertSz(pled->_yFirst >= 0, "CDisplayML::RecalcLines _yFirst < 0");
				pled->_yMatchOld  += rpOld->GetHeight();
				cliBackedUp--;
			
				_prgliNew->Clear(AF_KEEPMEM);	// Discard new line
				if (!(rpOld++))					// Next line
					cchSkip = 0;
			}
			else								// No match in the line, so 
				cchSkip = 0;					//  this line is the first to
		}										//  be edited

		Assert( !!(pliNew->_bFlags & fliFirstInPara) == !!fFirstInPara);
		fFirstInPara = pliNew->_cchEOP;
		yHeightPrev	 = yHeight;
		yHeight		+= pliNew->GetHeight();
		cchEdit		-= pliNew->_cch;

		if(fBackground && (GetTickCount() >= _dwBgndTickMax))
		{
			fDone = FALSE;						// took too long, stop for now
			goto no_match;
		}

		if(fWait && yHeight > _yWait && (LONG) me.GetCp() > _cpWait
			&& cliWait-- <= 0)
		{
			// Not really done, just past region we're waiting for
			// so let background recalc take it from here
			fDone = FALSE;
			goto no_match;
		}
	}											// while(cchEdit > 0) { }

   	Tracef(TRCSEVINFO, "Done recalcing edited text. Created %d new lines", _prgliNew->Count());

	// Edit lines have been exhausted.  Continue breaking lines,
	// but try to match new & old breaks

	wNumber = me._wNumber;
	while( (LONG) me.GetCp() < cchText )
	{
		// Assume there are no matches to try for
		BOOL	frpOldValid = FALSE;

		// If we run out of runs, then no match is possible. Therefore, 
		// we only try for a match as long as we have runs.
		if (fTryForMatch)
		{
			// We are trying for a match so assume that there
			// is a match after all
			frpOldValid = TRUE;

			// Look for match in old line break CArray
			lT = me.GetCp() - cchNew + cchOld;
			while (rpOld.IsValid() && pled->_cpMatchOld < lT)
			{
				pled->_yMatchOld  += rpOld->GetHeight();
				pled->_cpMatchOld += rpOld->_cch;

				if( !rpOld.NextRun() )
				{
					// No more line array entries so we can give up on
					// trying to match for good.
					fTryForMatch = FALSE;
					frpOldValid = FALSE;
					break;
				}
			} 
		}

		// If perfect match, stop
		if (frpOldValid && rpOld.IsValid() && pled->_cpMatchOld == lT && 
			rpOld->_cch && (!wNumber || me._wNumber < wNumber))
		{
           	Tracef(TRCSEVINFO, "Found match with old line #%d", rpOld.GetLineIndex());

			// Update fliFirstInPara flag in 1st old line that matches.  Note
			// that if the new array doesn't have any lines, we have to look
			// into the line array preceding the current change.
			rpOld->_bFlags |= fliFirstInPara;
			if( _prgliNew->Count() > 0 ) 
			{
				if(!(_prgliNew->Elem(_prgliNew->Count() - 1)->_cchEOP))
					rpOld->_bFlags &= ~fliFirstInPara;
			}
			else if( rpOld > pled->_iliFirst && pled->_iliFirst )
			{
				if(!rpOld[pled->_iliFirst - rpOld -1]._cchEOP )
					rpOld->_bFlags &= ~fliFirstInPara;
			}

			pled->_iliMatchOld = rpOld;

			// Replace old lines by new ones
			lT = rpOld - pled->_iliFirst;
			rpOld = pled->_iliFirst;
			if(!rpOld.Replace (lT, _prgliNew))
			{
				TRACEWARNSZ("CDisplayML::RecalcLines unable to alloc additional CLines in rpOld");
				goto errspace;
			}
			frpOldValid = rpOld.ChgRun(_prgliNew->Count());
			_prgliNew->Clear(AF_KEEPMEM);	 		// Clear aux array

			// Remember information about match after editing
			Assert((cp = rpOld.GetCp()) == (LONG) me.GetCp());
			pled->_yMatchNew	= yHeight;
			pled->_yMatchNewTop = yHeightPrev;
			pled->_iliMatchNew	= rpOld;
			pled->_cpMatchNew	= me.GetCp();

			// Compute height and cp after all matches
			_cpCalcMax = me.GetCp();

			if( frpOldValid && rpOld.IsValid() )
			{
				do
				{
					yHeight	   += rpOld->GetHeight();
					_cpCalcMax += rpOld->_cch;
				}
				while( rpOld.NextRun() );
			}

			// Make sure _cpCalcMax is sane after the above update
			AssertSz(_cpCalcMax <= cchText, 
				"CDisplayML::RecalcLines match extends beyond EOF");

			// We stop calculating here.Note that if _cpCalcMax < size 
			// of text, this means a background recalc is in progress.
			// We will let that background recalc get the arrays
			// fully in sync.  

			AssertSz(((_cpCalcMax == cchText) || _fBgndRecalc),
					"CDisplayML::Match less but no background recalc");

			if (_cpCalcMax != cchText)
			{
				// This is going to be finished by the background recalc
				// so set the done flag appropriately.
				fDone = FALSE;
			}
			goto match;

⌨️ 快捷键说明

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