📄 rtext.cpp
字号:
fIsAtBOP = !GetCp() || _rpTX.IsAfterEOP();
if (!fIsAtBOP && cch == cchOld && // Deleting EOP alone before
!rp.GetIch()) // new PARAFORMAT run start
{ // in para with more than EOP
cchMove = cchNextEOP; // Need to move chars up to
cpFormat += cchMove; // end of next para for
}
cchNextEOP += cchOld; // Count from GetCp() to EOP
tp.SetCp(GetCp()); // Back to this ptr's _cp
if(!fIsAtBOP)
cchPrevEOP = tp.FindEOP(tomBackward);// Get cch to start of para
// If deleting from within one format run up to or into another, set
// up to move last para in starting format run into the run following
// the deleted text
if(rp.GetFormat() != _rpPF.GetFormat() // Change of format during
&& !fIsAtBOP && !cchMove) // deleted text not starting
{ // at BOP
cchMove = cchPrevEOP; // Get cch to start of para
cpFormatMin += cchMove; // in this ptr's run for
} // moving into rp's run
}
Assert(cchNew >= 0 && cchOld >= 0);
if(!(cchNew + cchOld)) // Nothing to do (note: all
return 0; // these cch's are >= 0)
// Handle pre-replace range notifications. This method is very
// useful for delayed rendering of data copied to the clipboard.
pnm = GetPed()->GetNotifyMgr();
if( pnm )
{
pnm->NotifyPreReplaceRange((ITxNotify *)this, cpSave, cchOld,
cchNew, cpFormatMin, cpFormat + cchOld);
}
if(iFormat >= 0)
Check_rpCF();
// Get rid of objects first. This let's us guarantee that when we
// insert the objects as part of an undo, the objects themselves are
// restored _after_ their corresponding WCH_EMBEDDINGs have been
// added to the backing store.
if(GetObjectCount())
{
pobjmgr = GetPed()->GetObjectMgr();
if (NULL == pobjmgr)
{
TRACEWARNSZ("GetObjectMgr failed");
Assert(pobjmgr); //if we Got an ObjectCount, how did we not get an ObjectMgr?
return 0; //nothing we can do
}
pobjmgr->ReplaceRange(cpSave, cchOld, publdr);
}
if(IsRich() || IsIMERich()) // Rich text enabled
{
// The anti-events used below are a bit tricky (paeCF && paePF).
// Essentially, this call, CRchTxtPtr::ReplaceRange generates one
// 'combo' anti-event composed of up to two formatting AE's plus
// the text anti-event. These anti-events are combined together
// to prevent ordering problems during undo/redo.
cpFR = ReplaceRangeFormatting(cchOld + cchEndEOP, cchNew + cchEndEOP,
iFormat, publdr, &paeCF, &paePF, cchMove, cchPrevEOP, cchNextEOP);
if (cchEndEOP)
{
// If we added in the EOP we need to back up by the EOP so
// that the invariants don't get annoyed and the richtext object
// doesn't get out of sync.
_rpCF.AdvanceCp(-cchEndEOP);
_rpPF.AdvanceCp(-cchEndEOP);
}
if(cpFR < 0)
{
Tracef(TRCSEVERR, "ReplaceRangeFormatting(%ld, %ld, %ld) failed", GetCp(), cchOld, cchNew);
cch = 0;
goto Exit;
}
}
// As noted above in the call to ReplaceRangeFormatting, the anti-events
// paeCF and paePF, if non-NULL, were generated by ReplaceRangeFormatting.
// In order to solve ordering problems, the anti-event generated by this
// method is actually a combo anti-event of text && formatting AE's.
cch = _rpTX.ReplaceRange(cchOld, cchNew, pch, publdr, paeCF, paePF);
if (cch != cchNew)
{
Tracef(TRCSEVERR, "_rpTX.ReplaceRange(%ld, %ld, ...) failed", cchOld, cchNew);
#ifndef NODUMPFORMATRUNS
// Boy, out of memory or something bad. Dump our formatting and hope
// for the best.
//
// FUTURE: (alexgo) degrade more gracefully than loosing formatting
// info.
// Notify every interested party that they should dump their formatting
if( pnm )
{
pnm->NotifyPreReplaceRange(NULL, CONVERT_TO_PLAIN, 0, 0, 0, 0);
}
// Tell document to dump its format runs
GetPed()->GetTxtStory()->DeleteFormatRuns();
#endif
goto Exit;
}
AssertSz(!_rpPF.IsValid() || _rpPF.GetIch() || !GetCp() || _rpTX.IsAfterEOP(),
"CRchTxtPtr::ReplaceRange: EOP not at end of PF run");
// BUGBUG!! (alexgo) doesn't handle correctly the case where things fail
// (due to out of memory or whatever). See also notes in CTxtPtr::HandleReplaceRange
// Undo. The assert below is therefore somewhat bogus, but if it fires,
// then our floating ranges are going to be in trouble until we fix
// up the logic here.
Assert(cch == cchNew);
Exit:
#ifdef DEBUG
// test the invariant again before calling out to replace range notification;
// in this way, we can catch bugs earlier. The invariant has its own
// scope for convenience.
if( 1 )
{
_TEST_INVARIANT_
}
#endif
if( pnm )
{
pnm->NotifyPostReplaceRange((ITxNotify *)this, cpSave, cchOld, cch,
cpFormatMin, cpFormat + cchOld);
}
GetPed()->GetCallMgr()->SetChangeEvent(CN_TEXTCHANGED);
return cch;
}
/*
* CRchTxtPtr::InitRunPtrs(cp)
*
* @mfunc
* Initialize Run Ptrs of this rich-text ptr to correspond to
* document given by ped and to cp given by cp.
*/
void CRchTxtPtr::InitRunPtrs(
LONG cp) // @parm character position to move RunPtrs to
{
TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CRchTxtPtr::InitRunPtrs");
CTxtStory *pStory;
AssertSz(GetPed(), "RTP::InitRunPtrs: illegal GetPed()");
if( IsRich() || IsIMERich() )
{
pStory = GetPed()->GetTxtStory();
if(pStory->_pCFRuns) // and there's RichData,
{ // initialize format-run ptrs
_rpCF.SetRunArray((CRunArray *)pStory->_pCFRuns);
_rpCF.BindToCp(cp);
}
if (pStory->_pPFRuns)
{
_rpPF.SetRunArray((CRunArray *)pStory->_pPFRuns);
_rpPF.BindToCp(cp);
}
}
}
/*
* CRchTxtPtr::SetRunPtrs(cp, cpFrom)
*
* @mfunc set Run Ptrs of this rich-text ptr to correspond to cp
*
* @rdesc
* TRUE unless cp is outside of doc (in which case RunPtrs are
* set to nearest document end).
*/
BOOL CRchTxtPtr::SetRunPtrs(
LONG cp, // @parm character position to move RunPtrs to
LONG cpFrom) // @parm cp to start with
{
TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CRchTxtPtr::SetRunPtrs");
BOOL fRet = TRUE;
if(cpFrom && 2*cp >= cpFrom)
{
if (_rpCF.IsValid())
fRet = _rpCF.AdvanceCp(cp - cpFrom);
if(_rpPF.IsValid())
fRet = _rpPF.AdvanceCp(cp - cpFrom);
return fRet;
}
#ifdef LATER
if(_rpOB.IsValid())
fRet = _rpOB.RpSetCp(cp);
if(_rpRTF.IsValid())
fRet = _rpRTF.RpSetCp(cp);
#endif
if(_rpCF.IsValid())
fRet = _rpCF.BindToCp(cp);
if(_rpPF.IsValid())
fRet = _rpPF.BindToCp(cp);
return fRet;
}
/*
* CRchTxtPtr::ReplaceRangeFormatting(cchOld, cchNew, iFormat, publdr,
* ppaeCF, ppaePF, cchMove)
* @mfunc
* replace character and paragraph formatting at this text pointer
* using CCharFormat with index iFormat
*
* @rdesc
* count of new characters added
*
* @devnote
* moves _rpCF and _rpPF to end of replaced text
* moves format run arrays
* CCharFormat for iFormat is fully configured, i.e., no NINCHes
*/
INLINE LONG CRchTxtPtr::ReplaceRangeFormatting(
LONG cchOld, //@parm length of range to replace
LONG cchNew, //@parm length of replacement text
LONG iFormat, //@parm Char format to use
IUndoBuilder *publdr, //@parm UndoBuilder to receive antievents
IAntiEvent **ppaeCF, //@parm where to return 'extra' CF anti-events
IAntiEvent **ppaePF, //@parm where to return extra PF anti-events
LONG cchMove, //@parm cch to move between PF runs
LONG cchPrevEOP, //@parm cch from _cp back to prev EOP
LONG cchNextEOP) //@parm cch from _cp up to next EOP
{
TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CRchTxtPtr::ReplaceRangeFormatting");
LONG cp = GetCp();
ICharFormatCache * pcfc;
IParaFormatCache * ppfc;
DWORD iRunMerge = 0;
AssertSz(cchOld >= 0,
"CRchTxtPtr::ReplaceRangeFormatting: Illegal cchOld");
if(_rpCF.IsValid())
{
iRunMerge = _rpCF._iRun;
if( iRunMerge > 0 )
{
iRunMerge--;
}
if(FAILED(GetCharFormatCache(&pcfc)))
return -1; // Access to CF caches failed
if(cchOld > 0)
{ // add the soon-to-be deleted
if( publdr ) // formats to the undo list
{
*ppaeCF = gAEDispenser.CreateReplaceFormattingAE(
GetPed(), _rpCF, cchOld, pcfc, CharFormat);
}
// Delete/modify CF runs <-->
_rpCF.Delete(cchOld, pcfc, 0); // to cchOld chars
}
// If we deleted all of text in story, don't bother adding a new
// run. Else insert/modify CF runs corresponding to cchNew chars
//
// For IME composition in a plain text control, there is no
// trailing carriage return and thus need the extra test.
if(cchNew > 1 || cchNew && ( cchOld < (LONG)GetTextLength()
|| ( IsIMERich() && cchOld == (LONG)GetTextLength())))
{
_rpCF.InsertFormat(cchNew, iFormat, pcfc);
}
#ifdef DEBUG
else if( cchNew > 0 )
{
// Make sure that we don't have any format runs; we should
// be in the new document state.
Assert(!_rpCF.IsValid());
}
#endif // DEBUG
if((cchOld || cchNew) && _rpCF.IsValid())// Deleting all text
{ // invalidates _rpCF
_rpCF.MergeRuns(iRunMerge, pcfc);
_rpCF.BindToCp(cp + cchNew);
}
}
if(_rpPF.IsValid())
{
_rpPF.AdjustForward(); // Be absolutely sure that
// PF runs end with EOPs
iRunMerge = _rpPF._iRun;
if( iRunMerge > 0 )
{
iRunMerge--;
}
if(FAILED(GetParaFormatCache(&ppfc)))
return -1; // Access to PF caches failed
if(cchOld) // Delete cchOld from PF runs
{ // add the soon-to-be deleted
if( publdr ) // formats to the undo list
{
CFormatRunPtr rp(_rpPF);
rp.AdvanceCp(cchPrevEOP);
*ppaePF = gAEDispenser.CreateReplaceFormattingAE(GetPed(),
rp, cchNextEOP - cchPrevEOP, ppfc, ParaFormat);
}
_rpPF.Delete(cchOld, ppfc, cchMove);
}
if(_rpPF.IsValid()) // Deleting all text
{ // invalidates _rpPF
_rpPF.AdjustForward();
_rpPF.GetRun(0)->_cch += cchNew; // Insert cchNew into current
_rpPF._ich += cchNew; // PF run
if(cchOld || cchNew)
{
_rpPF.MergeRuns(iRunMerge, ppfc);
_rpPF.BindToCp(cp + cchNew);
}
}
}
return cchNew;
}
/*
* CRchTxtPtr::ExtendFormattingCRLF()
*
* @mfunc
* Use the same CCharFormat and CParaFormat indices for the EOP at
* this text ptr as those immediately preceeding it.
*
* @devnote
* Leaves this text ptr's format ptrs at run you get from AdjustBackward
* since this run ends up including the new text.
*/
void CRchTxtPtr::ExtendFormattingCRLF()
{
LONG cch = GetTextLength() - GetPed()->GetAdjustedTextLength();
IFormatCache *pf;
CNotifyMgr *pnm = GetPed()->GetNotifyMgr();
GetCharFormatCache((ICharFormatCache **)&pf);
_rpCF.AdjustFormatting(cch, pf);
GetParaFormatCache((IParaFormatCache **)&pf);
_rpPF.AdjustFormatting(cch, pf);
if( pnm )
{
// we assume that Cch is positive (or zero) here
Assert(cch >= 0);
pnm->NotifyPostReplaceRange((ITxNotify *)this, INFINITE, 0, 0,
GetCp(), GetCp() + cch);
}
}
/*
* CRchTxtPtr::IsRich()
*
* @mfunc
* Determine whether rich-text operation is operable
*
* @rdesc
* TRUE if associated CTxtEdit::_fRich = 1, i.e., control is allowed
* to be rich.
*/
BOOL CRchTxtPtr::IsRich()
{
TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CRchTxtPtr::IsRich");
return GetPed()->IsRich();
}
/*
* CRchTxtPtr::IsIMERich() const
*
* @mfunc
* This allow CF runs during plain text IME composition.
*
* @rdesc
* TRUE if not IsRich() and IME composition is occuring.
*/
BOOL CRchTxtPtr::IsIMERich() const
{
TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CRchTxtPtr::IsIMERich");
CTxtEdit *ped;
ped = GetPed();
Assert(ped);
return !ped->_fRich && ped->IsIMEComposition();
}
/*
* CRchTxtPtr::Check_rpCF()
*
* @mfunc
* enable _rpCF if it's not already enabled
*
* @rdesc
* TRUE if _rpCF is enabled
*
* FUTURE (murrays)
* Combine more of Check_rpCF and Check_rpPF. Maybe define common routine:
*
* BOOL CRchTxtPtr::Check_rp(CFormatPtr& rp, DWORD cbOffset)
*
* called by
*
* Check_rp (_rpCF, offsetof(CTxtStory, _pCFRuns))
*
* Note that cbOffset arg turns into a fast 2-byte constant push on x86
*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -