696 lines
16 KiB
C++
696 lines
16 KiB
C++
/*
|
|
* LINE.CPP
|
|
*
|
|
* Purpose:
|
|
* CLine class
|
|
*
|
|
* Authors:
|
|
* RichEdit 1.0 code: David R. Fulmer
|
|
* Christian Fortini (initial conversion to C++)
|
|
* Murray Sargent
|
|
*
|
|
* Copyright (c) 1995-1998 Microsoft Corporation. All rights reserved.
|
|
*/
|
|
|
|
#include "_common.h"
|
|
#include "_line.h"
|
|
#include "_measure.h"
|
|
#include "_render.h"
|
|
#include "_disp.h"
|
|
#include "_edit.h"
|
|
|
|
ASSERTDATA
|
|
|
|
/*
|
|
* CLine::Measure(&me, cchMax, xWidth, uiFlags, pliTarget)
|
|
*
|
|
* @mfunc
|
|
* Computes line break (based on target device) and fills
|
|
* in this CLine with resulting metrics on rendering device
|
|
*
|
|
* @rdesc
|
|
* TRUE if OK
|
|
*
|
|
* @devnote
|
|
* me is moved past line (to beginning of next line). Note: CLock is
|
|
* needed in the main four routines (Measure, MeasureText, CchFromXPos,
|
|
* and RenderLine), since they use the global (shared) fc().GetCcs()
|
|
* facility and may use the LineServices global g_plsc and g_pols.
|
|
*/
|
|
BOOL CLine::Measure(
|
|
CMeasurer& me, //@parm Measurer pointing at text to measure
|
|
LONG cchMax, //@parm Max cch to measure
|
|
LONG xWidth, //@parm Width of line in device units
|
|
UINT uiFlags, //@parm Flags
|
|
CLine * pliTarget) //@parm Returns target-device line metrics (optional)
|
|
{
|
|
TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CLine::Measure");
|
|
|
|
CLock lock;
|
|
BOOL fFirstInPara = uiFlags & MEASURE_FIRSTINPARA;
|
|
BOOL fMultiLine = me.GetPdp()->IsMultiLine();
|
|
BOOL fRet;
|
|
|
|
if(fMultiLine && fFirstInPara && me.GetPrevChar() == VT)
|
|
{
|
|
fFirstInPara = FALSE;
|
|
uiFlags &= ~MEASURE_FIRSTINPARA;
|
|
}
|
|
|
|
if(!(uiFlags & MEASURE_DONTINIT))
|
|
me.NewLine(fFirstInPara);
|
|
|
|
else if(fFirstInPara)
|
|
me._li._bFlags |= fliFirstInPara;
|
|
|
|
BYTE bNumber = me._wNumber < 256 // Store current para # offset
|
|
? me._wNumber : 255;
|
|
me._li._bNumber = bNumber;
|
|
|
|
#ifdef LINESERVICES
|
|
CMeasurer *pmeSave;
|
|
COls * pols = me.GetPols(&pmeSave); // Try for LineServices object
|
|
if(pols) // Got it: use LineServices
|
|
{
|
|
fRet = pols->MeasureLine(xWidth, pliTarget);
|
|
pols->SetMeasurer(pmeSave); // Restore previous pme
|
|
}
|
|
else // LineServices not active
|
|
#endif
|
|
fRet = me.MeasureLine(cchMax, xWidth, uiFlags, pliTarget);
|
|
|
|
if(!fRet)
|
|
return FALSE;
|
|
|
|
*this = me._li; // Copy over line info
|
|
|
|
if(!fMultiLine) // Single-line controls can't
|
|
return TRUE; // have paragraph numbering
|
|
|
|
if(me.IsInOutlineView())
|
|
{
|
|
if(IsHeadingStyle(me._pPF->_sStyle)) // Store heading number if relevant
|
|
_nHeading = (BYTE)(-me._pPF->_sStyle - 1);
|
|
|
|
if(me._pPF->_wEffects & PFE_COLLAPSED) // Cache collapsed bit
|
|
_fCollapsed = TRUE;
|
|
}
|
|
|
|
_bNumber = bNumber;
|
|
|
|
if(_bFlags & fliHasEOP) // Check for new para number
|
|
{
|
|
const CParaFormat *pPF = me.GetPF();
|
|
|
|
me._wNumber = (WORD)pPF->UpdateNumber(me._wNumber, me._pPF);
|
|
_fNextInTable = pPF->InTable() && me.GetCp() < me.GetTextLength();
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* CLine::Render(&re)
|
|
*
|
|
* @mfunc
|
|
* Render visible part of this line
|
|
*
|
|
* @rdesc
|
|
* TRUE iff successful
|
|
*
|
|
* @devnote
|
|
* re is moved past line (to beginning of next line).
|
|
* FUTURE: the RenderLine functions return success/failure.
|
|
* Could do something on failure, e.g., be specific and fire
|
|
* appropriate notifications like out of memory.
|
|
*/
|
|
BOOL CLine::Render(
|
|
CRenderer& re) //@parm Renderer to use
|
|
{
|
|
if(_fCollapsed) // Line is collapsed in Outline view
|
|
{
|
|
re.Advance(_cch); // Bypass line
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL fRet;
|
|
CLock lock;
|
|
POINT pt = re.GetCurPoint();
|
|
|
|
#ifdef LINESERVICES
|
|
CMeasurer *pmeSave;
|
|
COls *pols = re.GetPols(&pmeSave); // Try for LineServices object
|
|
if(pols)
|
|
{
|
|
fRet = pols->RenderLine(*this);
|
|
pols->SetMeasurer(pmeSave); // Restore previous pme
|
|
}
|
|
else
|
|
#endif
|
|
fRet = re.RenderLine(*this);
|
|
|
|
pt.y += GetHeight(); // Advance to next line position
|
|
re.SetCurPoint(pt);
|
|
return fRet;
|
|
}
|
|
|
|
/*
|
|
* CLine::CchFromXPos(&me, x, pdispdim, pHit)
|
|
*
|
|
* @mfunc
|
|
* Computes cch corresponding to x position in a line.
|
|
* Used for hit testing.
|
|
*
|
|
* @rdesc
|
|
* cch found up to the x coordinate x
|
|
*
|
|
* @devnote
|
|
* me is moved to the cp at the cch offset returned
|
|
*/
|
|
LONG CLine::CchFromXpos(
|
|
CMeasurer& me, //@parm Measurer position at start of line
|
|
POINT pt, //@parm pt.x is x coord to search for
|
|
CDispDim*pdispdim, //@parm Returns display dimensions
|
|
HITTEST *phit, //@parm Returns hit type at x
|
|
LONG *pcpActual) const //@parm actual CP above with display dimensions
|
|
{
|
|
TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CLine::CchFromXpos");
|
|
|
|
#ifdef Boustrophedon
|
|
//if(_pPF->_wEffects & PFE_BOUSTROPHEDON)
|
|
{
|
|
RECT rcView;
|
|
me.GetPed()->_pdp->GetViewRect(rcView, NULL);
|
|
pt.x = rcView.right - pt.x;
|
|
}
|
|
#endif
|
|
CLock lock;
|
|
const BOOL fFirst = _bFlags & fliFirstInPara;
|
|
*phit = HT_Text;
|
|
LONG cpActual = me.GetCp();
|
|
CDispDim dispdim;
|
|
|
|
me._li = *this;
|
|
me._li._cch = 0; // Default zero count
|
|
|
|
*phit = me.HitTest(pt.x);
|
|
|
|
if(*phit == HT_Text || *phit == HT_RightOfText) // To right of left margin
|
|
{
|
|
me.NewLine(fFirst);
|
|
|
|
#ifdef LINESERVICES
|
|
CMeasurer *pmeSave;
|
|
COls *pols = me.GetPols(&pmeSave);// Try for LineServices object
|
|
if(pols) // Got it: use LineServices
|
|
{
|
|
pols->CchFromXpos(pt, &dispdim, &cpActual);
|
|
pols->SetMeasurer(pmeSave); // Restore previous pme
|
|
}
|
|
else
|
|
#endif
|
|
if(me.Measure(pt.x - _xLeft, _cch,
|
|
MEASURE_BREAKBEFOREWIDTH | MEASURE_IGNOREOFFSET
|
|
| (fFirst ? MEASURE_FIRSTINPARA : 0)) >= 0)
|
|
{
|
|
LONG xWidthBefore = me._li._xWidth;
|
|
cpActual = me.GetCp();
|
|
if (me._li._cch < _cch)
|
|
{
|
|
dispdim.dx = me._xAddLast;
|
|
if (pt.x - _xLeft > xWidthBefore + dispdim.dx / 2)
|
|
{
|
|
me.Advance(1);
|
|
me._li._cch++;
|
|
me._li._xWidth += dispdim.dx;
|
|
}
|
|
}
|
|
}
|
|
|
|
me._rpCF.AdjustBackward();
|
|
DWORD dwEffects = me.GetCF()->_dwEffects;
|
|
if(dwEffects & CFE_LINK)
|
|
*phit = HT_Link;
|
|
else if(dwEffects & CFE_ITALIC)
|
|
*phit = HT_Italic;
|
|
|
|
#ifdef UNICODE_SURROGATES
|
|
// Until we support UTF-16 surrogate characters, don't allow hit in
|
|
// middle of a surrogate pair
|
|
if(IN_RANGE(0xDC00, me.GetChar(), 0xDFFF))
|
|
{
|
|
me.Advance(1);
|
|
me._li._cch++;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
if (pdispdim)
|
|
*pdispdim = dispdim;
|
|
if (pcpActual)
|
|
*pcpActual = cpActual;
|
|
|
|
return me._li._cch;
|
|
}
|
|
|
|
/*
|
|
* CLine::XposFromCch(&me, cch, taMode, pdispdim, pdy)
|
|
*
|
|
* @mfunc
|
|
* Measures cch characters starting from this text ptr, returning
|
|
* the width measured and setting yOffset = y offset relative to
|
|
* top of line and dx = halfwidth of character at me.GetCp() + cch.
|
|
* Used for caret placement and object location. pdx returns offset
|
|
* into the last char measured (at me.GetCp + cch) if taMode includes
|
|
* TA_CENTER (dx = half the last char width) or TA_RIGHT (dx = whole
|
|
* char width). pdy returns the vertical offset relative to the top
|
|
* of the line if taMode includes TA_BASELINE or TA_BOTTOM.
|
|
*
|
|
* @rdesc
|
|
* width of measured text
|
|
*
|
|
* @devnote
|
|
* me may be moved.
|
|
*/
|
|
LONG CLine::XposFromCch(
|
|
CMeasurer& me, //@parm Measurer pointing at text to measure
|
|
LONG cch, //@parm Max cch to measure
|
|
UINT taMode, //@parm Text-align mode
|
|
CDispDim * pdispdim, //@parm display dimensions
|
|
LONG * pdy) const //@parm dy offset due to taMode
|
|
{
|
|
CLock lock;
|
|
LONG xWidth;
|
|
BOOL fPols = FALSE;
|
|
CDispDim dispdim;
|
|
LONG dy = 0;
|
|
|
|
#ifdef LINESERVICES
|
|
CMeasurer *pmeSave;
|
|
COls *pols = me.GetPols(&pmeSave); // Try for LineServices object
|
|
if(pols)
|
|
{ // Got it: use LineServices
|
|
if(cch)
|
|
taMode &= ~TA_STARTOFLINE; // Not start of line
|
|
if(cch != _cch)
|
|
taMode &= ~TA_ENDOFLINE; // Not end of line
|
|
|
|
xWidth = pols->MeasureText(cch, taMode, &dispdim);
|
|
pols->SetMeasurer(pmeSave); // Restore previous pme
|
|
fPols = TRUE;
|
|
}
|
|
else
|
|
#endif
|
|
xWidth = me.MeasureText(cch) + _xLeft;
|
|
|
|
if(taMode != TA_TOP)
|
|
{
|
|
// Check for vertical calculation request
|
|
if(taMode & TA_BASELINE) // Matches TA_BOTTOM and
|
|
{ // TA_BASELINE
|
|
if(!_fCollapsed)
|
|
{
|
|
dy = _yHeight;
|
|
AssertSz(_yHeight != -1, "control has no height; used to use default CHARFORMAT");
|
|
if((taMode & TA_BASELINE) == TA_BASELINE)
|
|
dy -= _yDescent; // Need "== TA_BASELINE" to
|
|
} // distinguish from TA_BOTTOM
|
|
}
|
|
// Check for horizontal calculation request
|
|
if(taMode & TA_CENTER && !fPols) // If align to center or right of
|
|
{
|
|
if (cch == 0)
|
|
dispdim.dx = me.MeasureText(1) + _xLeft - xWidth;
|
|
else
|
|
dispdim.dx = me._xAddLast; // char, get char width
|
|
}
|
|
}
|
|
|
|
if (!fPols)
|
|
{
|
|
if((taMode & TA_CENTER) == TA_CENTER)
|
|
xWidth += dispdim.dx / 2;
|
|
else if (taMode & TA_RIGHT)
|
|
xWidth += dispdim.dx;
|
|
}
|
|
|
|
if (pdispdim)
|
|
*pdispdim = dispdim;
|
|
if (pdy)
|
|
*pdy = dy;
|
|
|
|
return xWidth;
|
|
}
|
|
|
|
/*
|
|
* CLine::GetHeight()
|
|
*
|
|
* @mfunc
|
|
* Get line height unless in outline mode and collasped, in
|
|
* which case get 0.
|
|
*
|
|
* @rdesc
|
|
* Line height (_yHeight), unless in outline mode and collapsed,
|
|
* in which case 0.
|
|
*/
|
|
LONG CLine::GetHeight() const
|
|
{
|
|
return _fCollapsed ? 0 : _yHeight;
|
|
}
|
|
|
|
BOOL CLine::IsEqual(CLine& li)
|
|
{
|
|
// CF - I dont know which one is faster
|
|
// MS3 - CompareMemory is certainly smaller
|
|
// return !CompareMemory (this, pli, sizeof(CLine) - 4);
|
|
return _xLeft == li._xLeft &&
|
|
_xWidth == li._xWidth &&
|
|
_yHeight == li._yHeight &&
|
|
_yDescent == li._yDescent &&
|
|
_cch == li._cch &&
|
|
_cchWhite == li._cchWhite;
|
|
}
|
|
|
|
|
|
// ===================== CLinePtr: Line Run Pointer ==========================
|
|
|
|
|
|
CLinePtr::CLinePtr(CDisplay *pdp)
|
|
{
|
|
TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CLinePtr::CLinePtr");
|
|
|
|
_pdp = pdp;
|
|
_pLine = NULL;
|
|
_pdp->InitLinePtr(* this);
|
|
}
|
|
|
|
void CLinePtr::Init (CLine & line)
|
|
{
|
|
TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CLinePtr::Init");
|
|
|
|
_pRuns = 0;
|
|
_pLine = &line;
|
|
_iRun = 0;
|
|
_ich = 0;
|
|
}
|
|
|
|
void CLinePtr::Init (CLineArray & line_arr)
|
|
{
|
|
TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CLinePtr::Init");
|
|
|
|
_pRuns = (CRunArray *) & line_arr;
|
|
_iRun = 0;
|
|
_ich = 0;
|
|
}
|
|
|
|
void CLinePtr::RpSet(LONG iRun, LONG ich)
|
|
{
|
|
TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CLinePtr::RpSet");
|
|
|
|
// See if this is a multi-line ptr
|
|
if(_pRuns)
|
|
CRunPtr<CLine>::SetRun(iRun, ich);
|
|
else
|
|
{
|
|
// single line, just reinit and set _ich
|
|
AssertSz(iRun == 0, "CLinePtr::RpSet() - single line and iRun != 0");
|
|
_pdp->InitLinePtr(* this); // to line 0
|
|
_ich = ich;
|
|
}
|
|
}
|
|
|
|
// Move runptr by a certain number of cch/runs
|
|
|
|
BOOL CLinePtr::RpAdvanceCp(LONG cch)
|
|
{
|
|
TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CLinePtr::RpAdvanceCp");
|
|
|
|
// See if this is a multi-line ptr
|
|
|
|
if(_pRuns)
|
|
return (cch == CRunPtr<CLine>::AdvanceCp(cch));
|
|
|
|
return RpAdvanceCpSL(cch);
|
|
}
|
|
|
|
BOOL CLinePtr::operator --(int)
|
|
{
|
|
TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CLinePtr::operator --");
|
|
|
|
return _pRuns ? PrevRun() : OperatorPostDeltaSL(-1);
|
|
}
|
|
|
|
BOOL CLinePtr::operator ++(int)
|
|
{
|
|
TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CLinePtr::operator ++");
|
|
|
|
return _pRuns ? NextRun() : OperatorPostDeltaSL(+1);
|
|
}
|
|
|
|
/*
|
|
* CLinePtr::RpAdvanceCpSL(cch)
|
|
*
|
|
* @mfunc
|
|
* move this line pointer forward or backward on the line
|
|
*
|
|
* @rdesc
|
|
* TRUE iff could advance cch chars within current line
|
|
*/
|
|
BOOL CLinePtr::RpAdvanceCpSL(
|
|
LONG cch) //@parm signed count of chars to advance by
|
|
{
|
|
TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CLinePtr::RpAdvanceCpSL");
|
|
|
|
Assert(!_pRuns);
|
|
|
|
if(!_pLine)
|
|
return FALSE;
|
|
|
|
_ich += cch;
|
|
|
|
if(_ich < 0)
|
|
{
|
|
_ich = 0;
|
|
return FALSE;
|
|
}
|
|
|
|
if(_ich > _pLine->_cch)
|
|
{
|
|
_ich = _pLine->_cch;
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* CLinePtr::OperatorPostDeltaSL(Delta)
|
|
*
|
|
* Purpose:
|
|
* Implement line-ptr ++ and -- operators for single-line case
|
|
*
|
|
* Arguments:
|
|
* Delta 1 for ++ and -1 for --
|
|
*
|
|
* Return:
|
|
* TRUE iff this line ptr is valid
|
|
*/
|
|
BOOL CLinePtr::OperatorPostDeltaSL(LONG Delta)
|
|
{
|
|
TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CLinePtr::OperatorPostDeltaSL");
|
|
|
|
AssertSz(_iRun <= 1 && !_pRuns,
|
|
"LP::++: inconsistent line ptr");
|
|
|
|
if(_iRun == -Delta) // Operation validates an
|
|
{ // invalid line ptr by moving
|
|
_pdp->InitLinePtr(* this); // to line 0
|
|
return TRUE;
|
|
}
|
|
|
|
_iRun = Delta; // Operation invalidates this line
|
|
_ich = 0; // ptr (if it wasn't already)
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
CLine * CLinePtr::operator ->() const
|
|
{
|
|
return _pRuns ? (CLine *)_pRuns->Elem(_iRun) : _pLine;
|
|
}
|
|
|
|
CLine * CLinePtr::GetLine() const
|
|
{
|
|
return _pRuns ? (CLine *)_pRuns->Elem(_iRun) : _pLine;
|
|
}
|
|
|
|
CLine & CLinePtr::operator *() const
|
|
{
|
|
return *(_pRuns ? (CLine *)_pRuns->Elem(_iRun) : _pLine);
|
|
}
|
|
|
|
CLine & CLinePtr::operator [](LONG dRun)
|
|
{
|
|
TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CLinePtr::operator []");
|
|
|
|
if(_pRuns)
|
|
return *(CLine *)CRunPtr<CLine>::GetRun(dRun);
|
|
|
|
AssertSz(dRun + _iRun == 0 ,
|
|
"LP::[]: inconsistent line ptr");
|
|
|
|
return *(CLine *)CRunPtr<CLine>::GetRun(_iRun);
|
|
}
|
|
|
|
BOOL CLinePtr::IsValid()
|
|
{
|
|
return !_pRuns ? _pLine != NULL : CRunPtrBase::IsValid();
|
|
}
|
|
|
|
/*
|
|
* CLinePtr::RpSetCp(cp, fAtEnd)
|
|
*
|
|
* Purpose
|
|
* Set this line ptr to cp allowing for ambigous cp and taking advantage
|
|
* of _cpFirstVisible and _iliFirstVisible
|
|
*
|
|
* Arguments:
|
|
* cp position to set this line ptr to
|
|
* fAtEnd if ambiguous cp:
|
|
* if fAtEnd = TRUE, set this line ptr to end of prev line;
|
|
* else set to start of line (same cp, hence ambiguous)
|
|
* Return:
|
|
* TRUE iff able to set to cp
|
|
*/
|
|
BOOL CLinePtr::RpSetCp(
|
|
LONG cp,
|
|
BOOL fAtEnd)
|
|
{
|
|
TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CLinePtr::RpSetCp");
|
|
|
|
_ich = 0;
|
|
if(!_pRuns)
|
|
{
|
|
// This is a single line so just go straight to the single
|
|
// line advance logic. It is important to note that the
|
|
// first visible character is irrelevent to the cp advance
|
|
// for single line displays.
|
|
return RpAdvanceCpSL(cp);
|
|
}
|
|
|
|
BOOL fRet;
|
|
LONG cpFirstVisible = _pdp->GetFirstVisibleCp();
|
|
|
|
if(cp > cpFirstVisible / 2)
|
|
{ // cpFirstVisible closer than 0
|
|
_iRun = _pdp->GetFirstVisibleLine();
|
|
fRet = RpAdvanceCp(cp - cpFirstVisible);
|
|
}
|
|
else
|
|
fRet = (cp == CRunPtr<CLine>::BindToCp(cp)); // Start from 0
|
|
|
|
if(fAtEnd) // Ambiguous-cp caret position
|
|
AdjustBackward(); // belongs at prev EOL
|
|
|
|
return fRet;
|
|
}
|
|
|
|
/*
|
|
* CLinePtr::FindParagraph(fForward)
|
|
*
|
|
* @mfunc
|
|
* Move this line ptr to paragraph (fForward) ? end : start,
|
|
* and return change in cp
|
|
*
|
|
* @rdesc
|
|
* change in cp
|
|
*/
|
|
LONG CLinePtr::FindParagraph(
|
|
BOOL fForward) //@parm TRUE move to para end; else to para start
|
|
{
|
|
TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CLinePtr::FindParagraph");
|
|
|
|
LONG cch;
|
|
CLine * pLine = GetLine();
|
|
|
|
if(!fForward) // Go to para start
|
|
{
|
|
cch = 0; // Default already at para start
|
|
if (RpGetIch() != pLine->_cch ||
|
|
!(pLine->_bFlags & fliHasEOP)) // It isn't at para start
|
|
{
|
|
cch = -RpGetIch(); // Go to start of current line
|
|
while(!(pLine->_bFlags & fliFirstInPara) && (*this) > 0)
|
|
{
|
|
(*this)--; // Go to start of prev line
|
|
pLine = GetLine();
|
|
cch -= pLine->_cch; // Subtract # chars in line
|
|
}
|
|
_ich = 0; // Leave *this at para start
|
|
}
|
|
}
|
|
else // Go to para end
|
|
{
|
|
cch = GetCchLeft(); // Go to end of current line
|
|
|
|
while(((*this) < _pdp->LineCount() - 1 ||
|
|
_pdp->WaitForRecalcIli((LONG)*this + 1))
|
|
&& !((*this)->_bFlags & fliHasEOP))
|
|
{
|
|
(*this)++; // Go to start of next line
|
|
cch += (*this)->_cch; // Add # chars in line
|
|
}
|
|
_ich = (*this)->_cch; // Leave *this at para end
|
|
}
|
|
return cch;
|
|
}
|
|
|
|
/*
|
|
* CLinePtr::GetAdjustedLineLength
|
|
*
|
|
* @mfunc returns the length of the line _without_ EOP markers
|
|
*
|
|
* @rdesc LONG; the length of the line
|
|
*/
|
|
LONG CLinePtr::GetAdjustedLineLength()
|
|
{
|
|
CLine * pline = GetLine();
|
|
|
|
return pline->_cch - pline->_cchEOP;
|
|
}
|
|
|
|
/*
|
|
* CLinePtr::GetCchLeft()
|
|
*
|
|
* @mfunc
|
|
* Calculate length of text left in run starting at the current cp.
|
|
* Complements GetIch(), which is length of text up to this cp.
|
|
*
|
|
* @rdesc
|
|
* length of text so calculated
|
|
*/
|
|
LONG CLinePtr::GetCchLeft() const
|
|
{
|
|
return _pRuns ? CRunPtrBase::GetCchLeft() : _pLine->_cch - _ich;
|
|
}
|
|
|
|
/*
|
|
* CLinePtr::GetNumber()
|
|
*
|
|
* @mfunc
|
|
* Get paragraph number
|
|
*
|
|
* @rdesc
|
|
* paragraph number
|
|
*/
|
|
WORD CLinePtr::GetNumber()
|
|
{
|
|
if(!IsValid())
|
|
return 0;
|
|
|
|
_pLine = GetLine();
|
|
if(!_iRun && _pLine->_bNumber > 1)
|
|
_pLine->_bNumber = 1;
|
|
|
|
return _pLine->_bNumber;
|
|
}
|