📄 dispml.cpp
字号:
}
// Add a new line
pliNew = _prgliNew->Add(1, NULL);
if (!pliNew)
{
TRACEWARNSZ("CDisplayML::RecalcLines unable to alloc additional CLine in CLineArray");
goto errspace;
}
Tracef(TRCSEVINFO, "Measuring new line from cp = %d", me.GetCp());
// Stuff some text into new line
wNumber = me._wNumber;
if (!pliNew->Measure(me, -1, MEASURE_BREAKATWORD |
(fFirstInPara ? MEASURE_FIRSTINPARA : 0)))
{
Assert(FALSE);
goto err;
}
fFirstInPara = pliNew->_cchEOP;
yHeight += pliNew->GetHeight();
if(fBackground && GetTickCount() >= (DWORD)_dwBgndTickMax)
{
fDone = FALSE; // Took too long, stop for now
break;
}
if(fWait && yHeight > _yWait && (LONG) me.GetCp() > _cpWait
&& cliWait-- <= 0)
{ // Not really done, just past region we're
fDone = FALSE; // waiting for so let background recalc
break; // take it from here
}
} // while(me < cchText) ...
no_match:
// Didn't find match: whole line array from _iliFirst needs to be changed
pled->_iliMatchOld = Count();
pled->_cpMatchOld = cchText;
pled->_yMatchNew = yHeight;
pled->_yMatchNewTop = yHeightPrev;
pled->_yMatchOld = _yHeight;
_cpCalcMax = me.GetCp();
// Replace old lines by new ones
rpOld = pled->_iliFirst;
// We store the result from the replace because although it can fail the
// fields used for first visible must be set to something sensible whether
// the replace fails or not. Further, the setting up of the first visible
// fields must happen after the Replace because the lines could have
// changed in length which in turns means that the first visible position
// has failed.
fReplaceResult = rpOld.Replace(-1, _prgliNew);
// _iliMatchNew & _cpMatchNew are used for first visible constants so we
// need to set them to something reasonable. In particular the rendering
// logic expects _cpMatchNew to be set to the first character of the first
// visible line. rpOld is used because it is convenient.
// Note we can't use RpBindToCp at this point because the first visible
// information is screwed up because we may have changed the line that
// the first visible cp is on.
rpOld.BindToCp(me.GetCp());
pled->_iliMatchNew = rpOld.GetLineIndex();
pled->_cpMatchNew = me.GetCp() - rpOld.RpGetIch();
if (!fReplaceResult)
{
TRACEERRORSZ("CDisplayML::RecalcLines rpOld.Replace() failed");
goto errspace;
}
// Adjust first affected line if this line is gone
// after replacing by new lines
if(pled->_iliFirst >= (LONG)Count() && Count() > 0)
{
Assert(pled->_iliFirst == (LONG)Count());
pled->_iliFirst = Count() - 1;
pliNew = Elem(pled->_iliFirst);
pled->_yFirst -= pliNew->GetHeight();
AssertSz(pled->_yFirst >= 0, "CDisplayML::RecalcLines _yFirst < 0");
pled->_cpFirst -= pliNew->_cch;
}
match:
_fRecalcDone = fDone;
_fNeedRecalc = FALSE;
_yCalcMax = yHeight;
Tracef(TRCSEVINFO, "CDisplayML::RecalcLine(tpFirst, ...) - Done. Recalced down to line #%d", Count() - 1);
// Clear wait fields since we want caller's to set them up.
_yWait = -1;
_cpWait = -1;
if(fDone && fBackground)
{
TRACEINFOSZ("Background line recalc done");
_ped->TxKillTimer(RETID_BGND_RECALC);
_fBgndRecalc = FALSE;
_fRecalcDone = TRUE;
}
// Determine display height and update scrollbar
yHeightScrollNew = CalcScrollHeight(yHeight);
if (_fViewChanged ||
fDone && (yHeight != _yHeight || yHeightScrollNew != yHeightScrollOld)
|| yHeightScrollNew > yHeightScrollOld)
{
_yHeight = yHeight;
UpdateScrollBar(SB_VERT, TRUE);
}
// Determine display width and update scrollbar
xWidth = CalcDisplayWidth();
if(_fViewChanged || (fDone && xWidth != _xWidth) || xWidth > _xWidth)
{
_xWidth = xWidth;
UpdateScrollBar(SB_HORZ, TRUE);
}
_fViewChanged = FALSE;
// If not done, do the rest in background
if(!fDone && !fBackground)
fDone = StartBackgroundRecalc();
if(fDone)
{
CheckLineArray();
_fLineRecalcErr = FALSE;
}
#ifdef DEBUG
if( 1 )
{
_TEST_INVARIANT_
}
#endif // DEBUG
return TRUE;
errspace:
_ped->GetCallMgr()->SetOutOfMemory();
_fNeedRecalc = TRUE;
_cpCalcMax = _yCalcMax = 0;
_fLineRecalcErr = TRUE;
err:
if(!_fLineRecalcErr)
{
_cpCalcMax = me.GetCp();
_yCalcMax = yHeight;
}
TRACEERRORSZ("CDisplayML::RecalcLines() failed");
if(!_fLineRecalcErr)
{
_fLineRecalcErr = TRUE;
_ped->GetCallMgr()->SetOutOfMemory();
_fLineRecalcErr = FALSE; // fix up CArray & bail
}
pled->SetMax(this);
return FALSE;
}
/*
* CDisplayML::CalcDisplayWidth()
*
* @mfunc
* Computes and returns width of this display by walking line
* CArray and returning the widest line. Used for
* horizontal scroll bar routines
*
*/
LONG CDisplayML::CalcDisplayWidth ()
{
TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplayML::CalcDisplayWidth");
LONG ili = Count();
CLine * pli;
LONG xWidth = 0, lineWidth;
if(ili)
{
// Note: pli++ breaks array encapsulation (pli = &(*this)[ili] doesn't)
pli = Elem(0);
for(xWidth = 0; ili--; pli++)
{
lineWidth = pli->_xLeft + pli->_xWidth + pli->_xLineOverhang;
xWidth = max(xWidth, lineWidth);
}
}
return xWidth;
}
/*
* CDisplayML::StartBackgroundRecalc()
*
* @mfunc
* Starts background line recalc (at _cpCalcMax position)
*
*/
BOOL CDisplayML::StartBackgroundRecalc()
{
TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplayML::StartBackgroundRecalc");
if(_fBgndRecalc)
{
// Already in background recalc
return FALSE;
}
AssertSz(_cpCalcMax <= (LONG)_ped->GetTextLength(),
"CDisplayML::StartBackgroundRecalc _cpCalcMax > Text Length");
if (_cpCalcMax == (LONG)_ped->GetTextLength())
{
// Enough characters are recalc'd.
return TRUE;
}
if (!_ped->TxSetTimer(RETID_BGND_RECALC, cmsecBgndInterval))
{
// Could not instantiate a timer so wait for recalculation
WaitForRecalc(_ped->GetTextLength(), -1);
return TRUE;
}
_fRecalcDone = FALSE;
_fBgndRecalc = TRUE;
return FALSE;
}
/*
* CDisplayML::StepBackgroundRecalc()
*
* @mfunc
* Steps background line recalc (at _cpCalcMax position)
* Called by timer proc
*
*/
void CDisplayML::StepBackgroundRecalc()
{
TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplayML::StepBackgroundRecalc");
_TEST_INVARIANT_
if (!_fBgndRecalc)
{
// We aren't in a background recalc so we don't
// do anything.
return;
}
LONG cch = _ped->GetTextLength() - _cpCalcMax;
// Don't try recalc when processing OOM or had an error doing recalc or
// if we are asserting.
#ifdef DEBUG
if(_fInBkgndRecalc || _fLineRecalcErr || fInAssert)
{
if(_fInBkgndRecalc)
TRACEINFOSZ("avoiding reentrant background recalc");
else
TRACEINFOSZ("OOM: not stepping recalc");
return;
}
#else
if(_fInBkgndRecalc || _fLineRecalcErr )
return;
#endif
_fInBkgndRecalc = TRUE;
if (!IsActive())
{
// Background recalc is over if we are no longer active because
// we can no longer get the information we need for recalculating.
// But, if we are half recalc'd we need to set ourselves up to
// recalc again when we go active.
InvalidateRecalc();
cch = 0;
}
// Background recalc is over if no more characters or we are no longer
// active.
if(cch <= 0)
{
TRACEINFOSZ("Background line recalc done");
_ped->TxKillTimer(RETID_BGND_RECALC);
_fBgndRecalc = FALSE;
_fRecalcDone = TRUE;
_fInBkgndRecalc = FALSE;
CheckLineArray();
return;
}
_dwBgndTickMax = GetTickCount() + cmsecBgndBusy;
CRchTxtPtr tp(_ped, _cpCalcMax);
RecalcLines(tp, cch, cch, TRUE, FALSE, NULL);
_fInBkgndRecalc = FALSE;
}
/*
* CDisplayML::WaitForRecalc(cpMax, yMax)
*
* @mfunc
* Ensures that lines are recalced until a specific character
* position or ypos.
*
* @rdesc
* success
*/
BOOL CDisplayML::WaitForRecalc(
LONG cpMax, //@parm Position recalc up to (-1 to ignore)
LONG yMax) //@parm ypos to recalc up to (-1 to ignore)
{
TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplayML::WaitForRecalc");
_TEST_INVARIANT_
if (IsFrozen() || !_ped->fInplaceActive())
{
return TRUE;
}
BOOL fReturn = TRUE;
LONG cch;
if((yMax < 0 || yMax >= _yCalcMax) &&
(cpMax < 0 || cpMax >= _cpCalcMax))
{
cch = _ped->GetTextLength() - _cpCalcMax;
if(cch > 0 || Count() == 0)
{
HCURSOR hcur = NULL;
BOOL fSetCursor = (cch > NUMCHARFORWAITCURSOR);
_cpWait = cpMax;
_yWait = yMax;
if( fSetCursor )
{
hcur = SetCursor(LoadCursor(0, IDC_WAIT));
}
TRACEINFOSZ("Lazy recalc");
if(!_cpCalcMax || _fNeedRecalc )
{
fReturn = RecalcLines(TRUE);
if( !fReturn )
{
InitVars();
}
}
else
{
CRchTxtPtr tp(_ped, _cpCalcMax);
fReturn = RecalcLines(tp, cch, cch, FALSE, TRUE, NULL);
}
if( fSetCursor )
{
SetCursor(hcur);
}
}
else if( cch == 0 )
{
// if there was nothing else to calc, make sure that we think
// recalc is done.
#ifdef DEBUG
if( !_fRecalcDone )
{
TRACEWARNSZ("For some reason we didn't think background "
"recalc was done, but it was!!");
}
#endif // DEBUG
_fRecalcDone = TRUE;
}
}
// If the view rect changed, make sure to update the scrollbars
RecalcScrollBars();
return fReturn;
}
/*
* CDisplayML::WaitForRecalcIli(ili)
*
* @mfunc
* Wait until line array is recalculated up to line <p ili>
*
* @rdesc
* Returns TRUE if lines were recalc'd up to ili
*/
BOOL CDisplayML::WaitForRecalcIli (
LONG ili) //@parm Line index to recalculate line array up to
{
TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplayML::WaitForRecalcIli");
LONG cchGuess;
while(!_fRecalcDone && ili >= (LONG)Count())
{
// just go ahead and recalc everything.
cchGuess = _ped->GetTextLength();
if(!WaitForRecalc(cchGuess, -1))
return FALSE;
}
return ili < (LONG)Count();
}
/*
* CDisplayML::WaitForRecalcView()
*
* @mfunc
* Ensure visible lines are completly recalced
*
* @rdesc TRUE iff successful
*/
BOOL CDisplayML::WaitForRecalcView()
{
TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplayML::WaitForRecalcView");
return WaitForRecalc(-1, _yScroll + _yHeightView);
}
/*
* CDisplayML::InitLinePtr ( CLinePtr & plp )
*
* @mfunc
* Initialize a CLinePtr properly
*/
void CDisplayML::InitLinePtr (
CLinePtr & plp ) //@parm Ptr to line to initialize
{
TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplayML::InitLinePtr");
plp.Init( *this );
}
/*
* CDisplayML::GetLineText(ili, pchBuff, cchMost)
*
* @mfunc
* Copy given line of this display into a character buffer
*
* @rdesc
* number of character copied
*/
LONG CDisplayML::GetLineText(
LONG ili, //@parm Line to get text of
TCHAR *pchBuff, //@parm Buffer to stuff text into
LONG cchMost) //@parm Length of buffer
{
TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplayML::GetLineText");
_TEST_INVARIANT_
CTxtPtr tp (_ped, 0);
// FUTURE (alexgo, ricksa): This is called from EM_GETLINE whose parameter
// is a WPARAM which is unsigned we need to fix the type of ili.
if(ili >= 0 && (ili < (LONG)Count() || WaitForRecalcIli(ili)))
{
cchMost = min(cchMost, (LONG)Elem(ili)->_cch);
if(cchMost > 0)
{
tp.SetCp(CpFromLine(ili, NULL));
return tp.GetText(cchMost, pchBuff);
}
}
*pchBuff = TEXT('\0');
return 0;
}
/*
* CDisplayML::LineCount
*
* @mfunc returns the number of lines in this control. Note that for plain
* text mode, we will add on an extra line of the last character is
* a CR. This is for compatibility with MLE
*
* @rdesc LONG
*/
LONG CDisplayML::LineCount() const
{
LONG cLine = Count();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -