📄 measure.cpp
字号:
#endif // PWD_JUPITER
else if(IsInOutlineView() && IsHeadingStyle(_pPF->sStyle))
yHeightBullet = BITMAP_HEIGHT_HEADING + 1;
}
// If line spacing or space before/after, measure from beginning of line
if(_cch && (_pPF->bLineSpacingRule || _pPF->dySpaceBefore
|| _pPF->dySpaceAfter || fInTable))
{
Advance(-(LONG)_cch);
NewLine(fFirstInPara);
}
_bNumber = _wNumber < 256 ? _wNumber : 255; // Store current para # offset
_xLeft = MeasureLeftIndent(); // Set left indent
// Compute width to break out at
if(xWidthMax < 0)
{
xWidthMax = MaxWidth();
// MaxWidth includes the caret size.
xCaret = 0;
}
else
{
// (AndreiB) xWidthMax that's coming down to us is always calculated
// with respect to the screen DC. The only scenario it comes into play
// however is in TxGetNaturalSize, which may output a slightly
// different result because of that.
if (!_pdp->SameDevice(_pdd))
{
// xWidthMax is calculated to the size of the screen DC. If
// there is a target device with different characteristics
// we need to convert the width to the target device's width
xWidthMax = _pdd->ConvertXToDev(xWidthMax, _pdp);
}
}
// For overhang support, we test against this adjusted widthMax.
xWidthMaxOverhang = xWidthMax;
// Are we ignoring the offset of the characters for the measure?
if ((uiFlags & MEASURE_IGNOREOFFSET) == 0)
{
// No - then take it from the max
xWidthMaxOverhang -= (_xLineOverhang + xCaret);
}
// Compute max number of characters to process
cch = cchText - GetCp();
if(cchMax < 0 || cchMax > cch)
cchMax = cch;
cchNonWhite = _cch; // Default nonwhite parms
xWidthNonWhite = _xWidth;
for( ; cchMax > 0; // Measure up to cchMax
cchMax -= cchChunk, Advance(cchChunk)) // chars
{
pch = GetPch(cch);
cch = min(cch, cchMax); // Compute constant-format
cchChunk = GetCchLeftRunCF();
cch = min(cch, cchChunk); // Counter for next while
cchChunk = cch; // Save chunk size
if(GetCF()->dwEffects & CFE_HIDDEN) // Ignore hidden text
{
_cch += cchChunk;
continue;
}
if (_chPassword != 0)
{
// WARNING: pch cannot be incremented after this point.
// Be sure that any new code does not modify pch after
// it is set here when we deal with passwords.
pch = &_chPassword;
}
// Check if new character format run or whether we don't yet have
// a font.
if ( !_pccs || FormatIsChanged() )
{
// New CF run or format for this line not yet initialized
ResetCachediFormat();
// If the format has changed,we release our old Format cache
if( _pccs != NULL )
{
// Release previous char cache if this is a new CF run
_pccs->Release();
}
_pccs = fc().GetCcs(_hdcMeasure, GetCF(),
_pdp->GetZoomNumerator(),
_pdp->GetZoomDenominator(),
_yMeasurePerInch);
// If we couldn't get one, we are dead.
if(!_pccs)
{
// When zooming, we may fail in low mem situations in which case
// the text won't display. If there was a zoom factor try
// getting the character metrics without the zoom factor.
if (_pdp->GetZoomNumerator() != _pdp->GetZoomDenominator()) {
_pccs = fc().GetCcs(_hdcMeasure, GetCF(),
1, 1, _yMeasurePerInch);
}
if (!_pccs) {
AssertSz(FALSE, "CMeasurer::Measure could not get _pccs");
return MRET_FAILED;
}
}
if (_cch && (0 == GetIchRunCF()))
{
// This is not the first character in the line,
// therefore there are multiple character formats
// on the line so we want to remember to render
// this off screen.
_bFlags |= fliUseOffScreenDC;
}
}
// NOTE: Drawing with a dotted pen on the screen and in a
// compatible bit map does not seem to match on some hardware.
// If at some future point we do a better job of drawing the
// dotted underline, this statement block can be removed.
if (CFU_UNDERLINEDOTTED == _pccs->_bUnderlineType)
{
// We draw all dotted underline lines off screen to get
// a consistent display of the dotted line.
_bFlags |= fliUseOffScreenDC;
}
_xLineOverhang = _pccs->_xOverhang;
xWidthMaxOverhang = xWidthMax; // Overhang reduces max.
// Are we ignoring the offset of the characters for the measure?
if ((uiFlags & MEASURE_IGNOREOFFSET) == 0)
{
// No - then take it from the max
xWidthMaxOverhang -= (_pccs->_xOverhang + xCaret);
}
// Adjust line height for new format run
if(cch > 0 && *pch)
{
// Note: the EOP only contributes to the height calculation for the
// line if there are no non-white space characters on the line or
// the paragraph is a bullet paragraph. The bullet paragraph
// contribution to the line height is done in AdjustLineHeight.
if ((0 == cchNonWhite) || (*pch != CR && *pch != LF))
{
// Determine if the current run is the tallest text on this
// line and if so, increase the height of the line.
yHeightOld = _yHeight;
RecalcLineHeight();
// Test for a change in line height. This only happens when
// this is not the first character in the line and (surprise)
// the height changes.
if (yHeightOld && yHeightOld != _yHeight)
fHeightChange = TRUE;
}
}
while(cch > 0)
{ // Process next char
xAdd = 0; // Default zero width
AssertSz(_chPassword == 0 || pch == &_chPassword,
"CMeasurer::Measure pch set to invalid data");
ch = *pch;
#ifdef PWD_JUPITER
// GuyBark Jupiter: If this is the special character for preserving
// CRLF in table cells, measure it as if it were a space.
if(ch == 0xFFFA)
{
ch = ' ';
}
#endif // PWD_JUPITER
if(ch == WCH_EMBEDDING)
{
_bFlags |= fliHasOle;
pobj = ped->GetObjectMgr()->GetObjectFromCp
(GetCp() + cchChunk - cch);
if( pobj )
{
pobj->MeasureObj(_pdp, xAdd, objheight, _yDescent);
// Only update height for line if the object is going
// to be on this line.
if((!_cch || _xWidth + xAdd <= xWidthMaxOverhang)
&& objheight > _yHeight)
{
_yHeight = (short)objheight;
}
}
if(_xWidth + xAdd > xWidthMaxOverhang)
fLastChObj = TRUE;
}
// The following if succeeds if ch isn't a CELL, BS, TAB, LF,
// VT, FF, or CR
else if(!IN_RANGE(CELL, ch, CR)) // Not TAB or EOP
{
if(!_pccs->Include(ch, xAdd)) // Get char width
{
AssertSz(FALSE, "CMeasurer::Measure char not in font");
return MRET_FAILED;
}
#ifdef SOFTHYPHEN
if(ch == SOFTHYPHEN)
{
_bFlags |= fliHasTabs; // Setup RenderChunk()
if(_xWidth + xAdd < xWidthMaxOverhang || !_cch)
{
xSoftHyphen = xAdd; // Save soft hyphen width
xAdd = 0; // Use 0 unless at EOL
}
}
#endif
}
else if(ch == TAB || ch == CELL)
{
_bFlags |= fliHasTabs;
xAdd = MeasureTab(ch);
}
else // Done with line
goto eop; // Go process EOP chars
index = iSavedWidths++ & MAX_SAVED_WIDTHS;
savedWidths[ index ].width = xAdd;
savedWidths[ index ].xLineOverhang = _xLineOverhang;
savedWidths[ index ].yHeight = _yHeight;
savedWidths[ index ].yDescent = _yDescent;
_xWidth += xAdd;
if(_xWidth > xWidthMaxOverhang && _cch > 0)
goto overflow;
_cch++;
if (_chPassword == 0)
{
pch++;
}
cch--;
if((ped->IsIMEComposition() && 0 == cch) || ch != TEXT(' ') /*&& ch != TAB*/) // If not whitespace char,
{
cchNonWhite = _cch; // update nonwhitespace
xWidthNonWhite = _xWidth; // count and width
}
} // while(cch > 0)
} // for(;cchMax > 0;...)
goto eol; // All text exhausted
// End Of Paragraph char encountered (CR, LF, VT, or FF, but mostly CR)
eop:
Advance(cchChunk - cch); // Position tp at EOP
cch = AdvanceCRLF(); // Bypass possibly multibyte EOP
_cchEOP = cch; // Store EOP cch
_cch += cch; // Increment line count
if(ch == CR) // Get new para number
{
const CParaFormat *pPF = GetPF();
_wNumber = pPF->UpdateNumber(_wNumber, _pPF);
_fNextInTable = pPF->InTable() && GetCp() < cchText;
}
AssertSz(ped->Get10Mode() || cch == 1,
"CMeasurer::Measure: EOP isn't a single char");
AssertSz(ped->TxGetMultiLine() || GetCp() == cchText,
"CMeasurer::Measure: EOP in single-line control");
eol: // End of current line
if(uiFlags & MEASURE_BREAKATWORD) // Compute count of whitespace
{ // chars at EOL
_cchWhite = (SHORT)(_cch - cchNonWhite);
_xWidth = xWidthNonWhite;
}
goto done;
overflow: // Went past max width for line
_xWidth -= xAdd;
--iSavedWidths;
_xLineOverhang = savedWidths[iSavedWidths & MAX_SAVED_WIDTHS].xLineOverhang;
Advance(cchChunk - cch); // Position *this at overflow
// position
if(uiFlags & MEASURE_BREAKATWORD) // If required, adjust break on
{ // word boundary
// We should not have the EOP flag set here. The case to watch out
// for is when we reuse a line that used to have an EOP. It is the
// responsibility of the measurer to clear this flag as appropriate.
Assert(_cchEOP == 0);
_cchEOP = 0; // Just in case
if (ch == TAB || ch == CELL)
{
// If the last character measured is a tab, leave it on the
// next line to allow tabbing off the end of line as in Word
goto done;
}
LONG cpStop = GetCp(); // Remember current cp
cch = -FindWordBreak(WB_LEFTBREAK, _cch+1);
if (cch == 0 && fLastChObj) // If preceding char is an
{ // object, put current char
goto done; // on next line
}
Assert(cch >= 0);
if(cch + 1 < (LONG)_cch) // Break char not at BOL
{
ch = _rpTX.GetPrevChar();
if (ch == TAB || ch == CELL) // If break char is a TAB,
{ // put it on the next line
cch++; // as in Word
Advance(-1);
}
#ifdef SOFTHYPHEN
else if(ch == SOFTHYPHEN)
_xWidth += xSoftHyphen;
#endif
_cch -= cch;
}
else if(cch == (LONG)_cch && cch > 1 &&
_rpTX.GetChar() == ' ') // Blanks all the way back to
{ // BOL. Bypass first blank
Advance(1);
cch--;
_cch = 1;
}
else // Advance forward to end of
SetCp(cpStop); // measurement
Assert(_cch > 0);
// Now search at start of word to figure how many white chars at EOL
if(GetCp() < cchText)
{
pch = GetPch(cch);
cch = 0;
if(ped->_pfnWB((TCHAR *)pch, 0, sizeof(TCHAR), WB_ISDELIMITER))
{
cch = FindWordBreak(WB_RIGHT);
Assert(cch >= 0);
}
_cchWhite = (SHORT)cch;
_cch += cch;
if(_rpTX.IsAtEOP()) // skip *only* 1 EOP -jOn
{
_cchEOP = AdvanceCRLF();
_cch += _cchEOP;
goto done;
}
}
i = cpStop - GetCp();
if( i )
{
if ( i > 0 )
i += _cchWhite;
if (i > 0 && i < iSavedWidths && i < MAX_SAVED_WIDTHS)
{
while (i-- > 0)
{
iSavedWidths = (iSavedWidths - 1) & MAX_SAVED_WIDTHS;
_xWidth -= savedWidths[iSavedWidths].width;
}
_xLineOverhang = savedWidths[iSavedWidths].xLineOverhang;
_yHeight = savedWidths[iSavedWidths].yHeight;
_yDescent = savedWidths[iSavedWidths].yDescent;
}
else
{
// Need to recompute width from scratch.
_xWidth = -1;
lRet = MRET_NOWIDTH;
}
}
else
{
// i == 0 means that we are breaking on the first letter in a word.
// Therefore, we want to set the width to the total non-white space
// calculated so far because that does not include the size of the
// character that caused the break nor any of the white space
// preceeding the character that caused the break.
if (!fHeightChange)
{
_xWidth = xWidthNonWhite;
}
else
{
// Need to recompute from scratch so that we can get the
// correct height for the control
_xWidth = -1;
lRet = MRET_NOWIDTH;
}
}
}
else if(uiFlags & MEASURE_BREAKATWIDTH)
{
// Breaks at character closest to target width
if((_cch == 1) && (xWidthMax < _xWidth / 2))
{
_cch = 0;
_xWidth = 0;
Advance(-1);
}
if(xAdd && xWidthMax - _xWidth >= xAdd / 2)
{
_cch++;
_xWidth += xAdd;
Advance(1);
}
}
done:
// If no height yet, use default height
if(_yHeight == 0)
{
const CCharFormat *pcf = ped->GetCharFormat(-1);
CCcs * const pccs = fc().GetCcs(_hdcMeasure, pcf, _pdp->GetZoomNumerator(),
_pdp->GetZoomDenominator(), _yMeasurePerInch);
_yHeight = pccs->_yHeight;
_yDescent = pccs->_yDescent;
pccs->Release();
}
// Allow last minute adjustment to line height
if (yHeightBullet > _yHeight)
{
_yHeight = yHeightBullet;
}
_fStartsList = (_bNumber == 1 && fFirstInPara);
AdjustLineHeight();
return lRet;
}
/*
* CMeasurer::AdjustLineHeight()
*
* @mfunc
* Adjust for space before/after and line spacing rules.
* No effect for plain text.
*
* @future
* Base multiple line height calculations on largest font height rather
* than on line height (_yHeight), since the latter may be unduly large
* due to embedded objects. Word does this correctly.
*/
void CMeasurer::AdjustLineHeight()
{
TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CMeasurer::AdjustLineHeight");
if(!IsRich() || IsInOutlineView()) // Plain text and outline mode
return; // don't use special line
// spacings
const CParaFormat * pPF = _pPF;
DWORD dwRule = pPF->bLineSpacingRule;
LONG dyAfter = 0; // Default no space after
LONG dyBefore = 0; // Default no space before
LONG dySpacing = pPF->dyLineSpacing;
LONG yHeight = LYtoDY(dySpacing);
if(_bFlags & fliFirstInPara)
dyBefore = LYtoDY(pPF->dySpaceBefore); // Space before paragraph
if(yHeight < 0) // Negative heights mean use
_yHeight = -(SHORT)yHeight; // the magnitude exactly
else if(dwRule) // Line spacing rule is active
{
switch (dwRule)
{
case tomLineSpace1pt5:
dyAfter = _yHeight >> 1; // Half-line space after
break; // (per line)
case tomLineSpaceDouble:
dyAfter = _yHeight; // Full-line space after
break; // (per line)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -