📄 measure.cpp
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft shared
// source or premium shared source license agreement under which you licensed
// this source code. If you did not accept the terms of the license agreement,
// you are not authorized to use this source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the SOURCE.RTF on your install media or the root of your tools installation.
// THE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES.
//
/*
* @doc
*
* @module - MEASURE.C |
*
* CMeasurer class
*
* Authors:
* Original RichEdit code: David R. Fulmer <nl>
* Christian Fortini, Murray Sargent, Rick Sailor
*
*/
#include "_common.h"
#include "_measure.h"
#include "_font.h"
#include "_disp.h"
#include "_edit.h"
#include "_frunptr.h"
#include "_objmgr.h"
#include "_coleobj.h"
ASSERTDATA
// Default character format for a bullet
const CHARFORMAT cfBullet =
{
sizeof(CHARFORMAT),
0,
CFE_AUTOCOLOR + CFE_AUTOBACKCOLOR,
0,
0,
0,
SYMBOL_CHARSET,
(BYTE) FF_DONTCARE,
TEXT("Symbol")
};
const TCHAR chBullet = TEXT('\xB7');
// Note we set this maximum length as appropriate for Win95 since Win95 GDI can
// only handle 16 bit values. We don't special case this so that both NT and
// Win95 will behave the same way.
// Note that the following obscure constant was empirically determined on Win95.
const LONG lMaximumWidth = (3 * (LONG) SHRT_MAX) / 4;
CMeasurer::CMeasurer (const CDisplay* const pdp) :
CRchTxtPtr (pdp->GetED())
{
TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CMeasurer::CMeasurer");
_pdp = pdp;
_pdd = pdp;
_pccs = NULL;
_hdc = NULL;
_hdcMeasure = NULL;
_chPassword = GetPed()->TxGetPasswordChar();
SetNumber(0);
}
CMeasurer::CMeasurer (const CDisplay* const pdp, const CRchTxtPtr &tp) :
CRchTxtPtr (tp)
{
TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CMeasurer::CMeasurer");
_pdp = pdp;
_pdd = pdp;
_pccs = NULL;
_hdc = NULL;
_hdcMeasure = NULL;
_chPassword = GetPed()->TxGetPasswordChar();
SetNumber(0);
}
CMeasurer::~CMeasurer()
{
TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CMeasurer::~CMeasurer");
if(_pccs)
_pccs->Release();
// Releases the rendering dc
if (_hdc)
{
_pdd->ReleaseDC(_hdc);
}
// Releases the measuring dc
if (_hdcMeasure)
{
_pdd->ReleaseMeasureDC(_hdcMeasure);
}
}
/*
* CMeasurer::NewLine (fFirstInPara)
*
* @mfunc
* Initialize this measurer at the start of a new line
*/
void CMeasurer::NewLine(
BOOL fFirstInPara) //@parm Flag for setting up _bFlags
{
TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CMeasurer::NewLine");
CLine::Init(); // Zero all members
if(fFirstInPara)
_bFlags = fliFirstInPara; // Need to know if first in para
}
/*
* CMeasurer::NewLine(&li)
*
* @mfunc
* Initialize this measurer at the start of a given line
*/
void CMeasurer::NewLine(
const CLine &li)
{
TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CMeasurer::NewLine");
*this = li;
_cch = 0;
_cchWhite = 0;
_xWidth = 0;
// Can't calculate xLeft till we get an HDC
_xLeft = 0;
if(!GetPF()->IsListNumbered())
_bNumber = 0;
_wNumber = _bNumber;
}
/*
* CMeasurer::MaxWidth()
*
* @mfunc
* Get maximum width for line
*
* @rdesc
* Maximum width for a line
*/
LONG CMeasurer::MaxWidth()
{
LONG xWidth = lMaximumWidth;
if (_pdp->GetWordWrap() && !GetPF()->InTable())
{
// There is a caret only on the main display
LONG xCaret = _pdp->IsMain() ? dxCaret : 0;
// Calculate the width of the display
LONG xDispWidth = _pdp->GetMaxPixelWidth();
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
xDispWidth = _pdd->ConvertXToDev(xDispWidth, _pdp);
}
xWidth = xDispWidth - MeasureRightIndent() - _xLeft - xCaret;
}
return (xWidth > 0) ? xWidth : 0;
}
/*
* CMeasurer::MeasureText (cch)
*
* @mfunc
* Measure a stretch of text from current running position.
*
* @rdesc
* width of text (in device units), < 0 if failed
*/
LONG CMeasurer::MeasureText(
LONG cch) //@parm Number of characters to measure
{
TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CMeasurer::MeasureText");
LONG xWidth = _xWidth;
if (Measure (0x7fffffff, cch, 0) == MRET_FAILED)
return -1;
LONG xMaxWidth = MaxWidth();
return min(_xWidth - xWidth, xMaxWidth);
}
/*
* CMeasurer::MeasureLine (xWidthMax, cchMax, uiFlags, ppu, pliTarget)
*
* @mfunc
* Measure a line of text from current cp and determine line break.
* On return *this contains line metrics for _pdd device.
*
* @rdesc
* TRUE if success, FALSE if failed
*/
BOOL CMeasurer::MeasureLine(
LONG xWidthMax, //@parm max width to process (-1 uses CDisplay width)
LONG cchMax, //@parm Max chars to process (-1 if no limit)
UINT uiFlags, //@parm Flags controlling the process (see Measure())
CLine *pliTarget) //@parm Returns target-device line metrics (optional)
{
TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CMeasurer::MeasureLine");
LONG lRet;
LONG cp = GetCp();
const CDevDesc *pddTarget = NULL;
if (_pdp->GetWordWrap())
{
// Target devices are only interesting if word wrap is on because the
// only really interesting thing a target device can tell us is where
// the word breaks will occur.
pddTarget = _pdp->GetTargetDev();
if (pddTarget != NULL)
{
// If there is a target device, use that device to compute line
// breaks. This is followed with a recompute to get the actual
// measurements on the rendering device.
// ... but first releases the measuring dc
if (_hdcMeasure)
_pdd->ReleaseMeasureDC(_hdcMeasure);
_hdcMeasure = pddTarget->GetDC();
_yMeasurePerInch = GetDeviceCaps(_hdcMeasure, LOGPIXELSY);
_pdd = pddTarget;
if (_pccs != NULL)
{
_pccs->Release();
_pccs = NULL;
}
}
}
// Compute line break
lRet = Measure(xWidthMax, cchMax, uiFlags);
// Stop here if failed
if(lRet == MRET_FAILED)
return FALSE;
// Return target metrics if requested
if(pliTarget)
{
*pliTarget = *this;
}
if (pddTarget)
{
// First computation was with the target device so we need to recompute
// with the rendering device. Here we set the device to measure with
// back to the render device.
// ... first releases the current measuring dc
if (_hdcMeasure)
_pdd->ReleaseMeasureDC(_hdcMeasure);
_pdd = _pdp;
_hdcMeasure = _pdp->GetMeasureDC(&_yMeasurePerInch);
if (_pccs != NULL)
{
_pccs->Release();
_pccs = NULL;
}
// We just use this flag as an easy way to get the recomputation to occur.
lRet = MRET_NOWIDTH;
}
// Recompute metrics on rendering device
if(lRet == MRET_NOWIDTH)
{
LONG cch = _cch;
SHORT cchWhite = _cchWhite;
// Save the flags for this line because at least the EOP flag gets
// screwed up in the recalc and none of the flags will change based
// on the second recalc of the line. Ditto for numbering variables
BYTE bFlags = _bFlags;
BYTE bNumber = _bNumber;
BYTE cchEOP = _cchEOP;
WORD wNumber = _wNumber;
#ifdef PWD_JUPITER
// GuyBark Jupiter 31112: Store the current line height here.
int yHeightOld = _yHeight;
#endif // PWD_JUPITER
Advance(-cch); // move back to BOL
NewLine(uiFlags & MEASURE_FIRSTINPARA);
#ifdef PWD_JUPITER
// GuyBark Jupiter 31112: Say the line consists only of an EOP mark.
// This means Measure() will end up giving the line a default height.
// This is incorrect as the line should have the height of the EOP.
// So give the line the it's previous value here as a starting point.
// Measure() can set it to something else later if it wants to.
if(cch == cchWhite)
{
_yHeight = yHeightOld;
}
#endif // PWD_JUPITER
// (AndreiB) EOP flag would not get reset below because we excluded it
// from the second measure ( - cchWhite) By restoring it right here
// we ensure we know whether the line is at the end of para or not
// right from the beginning. This may seem somewhat hacky but it works.
_cchEOP = cchEOP;
#ifdef PWD_JUPITER
// GuyBark Jupiter 34903:
// I don't really know how this can happen, but the paragraph (_pPF)
// can be numbered here, but the measured details don't realize it.
// As a failsafe, make sure the measured details reflect the true
// paragraph attributes.
if(!_bNumber && // The measure details think this isn't numbered.
_pPF->wNumbering != 0) // But the paragraph details says it is numbered!
{
// Make all the measure numbering details current.
_bNumber = _pPF->wNumbering;
_wNumber = _pPF->wNumbering;
}
#endif // PWD_JUPITER
lRet = Measure(0x7fffffff, cch - cchWhite, uiFlags & MEASURE_FIRSTINPARA);
if(lRet != 0)
{
Assert(lRet != MRET_NOWIDTH);
return FALSE;
}
// Restore the flags and numbering variables
_bFlags = bFlags;
_bNumber = bNumber;
_cchEOP = cchEOP;
_wNumber = wNumber;
Assert((LONG)_cch == cch - cchWhite);
_cchWhite = cchWhite;
_cch = cch; // account for the white stuff at EOL
Advance(cchWhite); // skip white stuff that we did not remeasure
}
// Now that we know the line width, compute line shift due
// to alignment, and add it to the left position
_xLeft += MeasureLineShift();
return TRUE;
}
/*
* CMeasurer::RecalcLineHeight ()
*
* @mfunc
* Reset the height of the the line we are measuring if the new run of
* text is taller than the current maximum in the line.
*/
void CMeasurer::RecalcLineHeight()
{
TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CMeasurer::RecalcLineHeight");
// Compute line height
LONG yOffset = _pccs->_yOffset;
SHORT yHeight = _pccs->_yHeight;
SHORT yDescent = _pccs->_yDescent;
SHORT yAscent = yHeight - yDescent;
SHORT yAboveBase;
SHORT yBelowBase;
yAboveBase = max(yAscent, yAscent + yOffset);
yBelowBase = max(yDescent, yDescent - yOffset);
_yHeight = max(yAboveBase, _yHeight - _yDescent) +
max(yBelowBase, _yDescent);
_yDescent = max(yBelowBase, _yDescent);
}
/*
* CMeasurer::Measure (xWidthMax, cchMax, uiFlags)
*
* @mfunc
* Measure given amount of text, start at current running position
* and storing # chars measured in _cch.
* Can optionally determine line break based on a xWidthMax and
* break out at that point.
*
* @rdesc
* 0 success
* MRET_FAILED if failed
* MRET_NOWIDTH if second pass is needed to compute correct width
*
* @devnote
* The uiFlags parameter has the following meanings:
* MEASURE_FIRSTINPARA this is first line of paragraph
* MEASURE_BREAKATWORD break out on a word break
* MEASURE_BREAKATWIDTH break closest possible to xWidthMax
*/
LONG CMeasurer::Measure(
LONG xWidthMax, //@parm Max width of line (-1 uses CDisplay width)
LONG cchMax, //@parm Max chars to process (-1 if no limit)
UINT uiFlags) //@parm Flags controlling the process (see above)
{
TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CMeasurer::Measure");
LONG cch; // cchChunk count down
LONG cchChunk; // cch of cst-format contiguous run
LONG cchNonWhite; // cch of last nonwhite char in line
LONG cchText = GetTextLength();
unsigned ch; // Temporary char
BOOL fFirstInPara = uiFlags & MEASURE_FIRSTINPARA;
BOOL fLastChObj = FALSE;
LONG lRet = 0;
const TCHAR*pch;
CTxtEdit * ped = _pdp->GetED();
COleObject *pobj;
LONG objheight;
LONG yHeightBullet = 0;
LONG xCaret = dxCaret;
LONG xAdd; // Character width
#ifdef SOFTHYPHEN
LONG xSoftHyphen = 0; // Most recent soft hyphen width
#endif
LONG xWidthNonWhite; // xWidth for last nonwhite char in line
LONG xWidthMaxOverhang; // The max with the current run's overhang
// taken into consideration.
// These two variables are used to keep track of whether there is a height change
// so that we know whether we need to recalc the line in certain line break cases.
BOOL fHeightChange = FALSE;
LONG yHeightOld = 0;
const INT MAX_SAVED_WIDTHS = 31; // power of 2 - 1
INT i, index, iSavedWidths = 0;
struct {
LONG width;
LONG xLineOverhang;
LONG yHeight;
LONG yDescent;
} savedWidths[MAX_SAVED_WIDTHS+1];
_pPF = GetPF(); // Be sure current CParaFormat
// ptr is up to date
BOOL fInTable = _pPF->InTable();
WORD wNumbering = _pPF->wNumbering;
WORD wNumberingStyle = _pPF->wNumberingStyle;
if(IsInOutlineView())
{
if(IsHeadingStyle(_pPF->sStyle)) // Store heading number if relevant
_nHeading = -_pPF->sStyle - 1;
if(_pPF->wEffects & PFE_COLLAPSED) // Cache collapsed bit
_fCollapsed = TRUE;
}
if(!_hdcMeasure)
{
_hdcMeasure = _pdd->GetMeasureDC(&_yMeasurePerInch);
if(!_hdcMeasure)
{
AssertSz(FALSE, "CMeasurer::Measure could not get DC");
return MRET_FAILED;
}
}
// Init fliFirstInPara flag for new line
if(fFirstInPara)
{
_bFlags |= fliFirstInPara;
if(fInTable)
_bFlags |= fliUseOffScreenDC;
// Because measure bullet depends on the cp we need
// to measure it before we do the reset of our measuring
if(wNumbering)
#ifdef PWD_JUPITER // GuyBark Jupiter 34728: Pay attention to the returned bullet height!
yHeightBullet = MeasureBulletHeight();
#else
MeasureBulletHeight();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -